1. Load required libraries
library(ggplot2)
library(Hmisc)
library(multtest)
library(network)
library(igraph)

1a. Examine the relation between the transcription of bacterial sRNAs and their regulatory activities - Part I (Fig 1)

#Name of sRNAs shown in Fig 1 A-B
fig1.sRNAs<-c("spf","ryhB")
#Load the output of the Inferelator run
load("../Inferelator_output_files/Ecoli_8sRNAs/betas_frac_tp_100_perm_1--frac_fp_0_perm_1_1.1.RData")
load("../Inferelator_output_files/Ecoli_8sRNAs/combinedconf_frac_tp_100_perm_1--frac_fp_0_perm_1_1.1.RData")
load("../Inferelator_output_files/Ecoli_8sRNAs/params_and_input.RData")
#Extract expression response and design matrices
expression.response.matrix<-IN$final_response_matrix
expression.design.matrix<-IN$final_design_matrix
#This is the gold standard (prior) network
gs.matrix<-IN$gs.mat
#Matrix with regulators (TFs & sRNAs) activities
regulators.activities.matrix<-IN$tf.activities[[1]]
par(mfrow=c(1,2))
for(i in fig1.sRNAs)
{
  sRNA.activities<-regulators.activities.matrix[grep(i,rownames(regulators.activities.matrix)),]
  sRNA.transcriptional.profile<-expression.design.matrix[grep(i,rownames(expression.design.matrix)),]
  sRNA.priors<-rownames(gs.matrix)[which(gs.matrix[,grep(i,colnames(gs.matrix))]!=0)]
  sRNA.regulon.expression<-expression.response.matrix[sRNA.priors,]
  mean.expression.sRNA.regulon<-colMeans(sRNA.regulon.expression)
  plot(x=sRNA.transcriptional.profile,y=mean.expression.sRNA.regulon,col=rgb(1,0,0,1),lwd=1,xlab=paste(i,"transcription",sep=" "),ylab="Mean transcription of targets",cex=1.5, cex.lab=1.5,cex.axis=1.5)
  #Perform linear regression
  lr.sRNA.exp.regulon<-lm(mean.expression.sRNA.regulon ~ as.numeric(sRNA.transcriptional.profile))
  abline(lr.sRNA.exp.regulon,col="darkred",lwd=3,lty=2)
  plot(x=sRNA.activities,y=mean.expression.sRNA.regulon,col=rgb(1,0,0,1),lwd=1,xlab=paste(capitalize(i),"activity",sep=" "),ylab="",cex=1.5, cex.lab=1.5,cex.axis=1.5)
  #Perform linear regression
  lr.sRNA.activity.regulon<-lm(mean.expression.sRNA.regulon ~ as.numeric(sRNA.activities))
  abline(lr.sRNA.activity.regulon,col="darkred",lwd=3,lty=2)
}

#Create similar figure for FnrS activity (its transcriptional profile is not present in the expression matrix) 
  sRNA.activities<-regulators.activities.matrix[grep("FnrS",rownames(regulators.activities.matrix)),]
  sRNA.priors<-rownames(gs.matrix)[which(gs.matrix[,grep("FnrS",colnames(gs.matrix))]!=0)]
  sRNA.regulon.expression<-expression.response.matrix[sRNA.priors,]
  mean.expression.sRNA.regulon<-colMeans(sRNA.regulon.expression)
  plot(x=sRNA.activities,y=mean.expression.sRNA.regulon,col=rgb(1,0,0,1),lwd=1,xlab="FnrS activity",ylab="Mean transcription of targets",cex=1.5, cex.lab=1.5,cex.axis=1.5, main="Fig 1D")
  #Perform linear regression
  lr.sRNA.activity.regulon<-lm(mean.expression.sRNA.regulon ~ as.numeric(sRNA.activities))
  abline(lr.sRNA.activity.regulon,col="darkred",lwd=3,lty=2)

  #Create Fig 1C
  #Define correlation between sRNAs and their priors
  sRNAs<-colnames(IN$priors.mat)[140:147]
  correlation.sRNA.activities.targets.expression<-c()
  correlation.sRNA.expression.targets.expression<-c()
  for(t in sRNAs[-8])
  {
    sRNA.activities<-regulators.activities.matrix[t,]
    sRNA.expression<-expression.design.matrix[t,]
    sRNA.priors<-names(which(gs.matrix[,t]!=0))
    for(g in sRNA.priors)
    {
    correlation.sRNA.activities.targets.expression<-c(correlation.sRNA.activities.targets.expression,
                                                      cor(sRNA.activities,expression.response.matrix[g,]))
    correlation.sRNA.expression.targets.expression<-c(correlation.sRNA.expression.targets.expression,
                                                      cor(sRNA.expression,expression.response.matrix[g,]))  
    }
  }
temporal.matrix<-rbind(cbind(correlation.sRNA.expression.targets.expression,rep("Expression",length(correlation.sRNA.expression.targets.expression))),cbind(correlation.sRNA.activities.targets.expression,rep("Activity",length(correlation.sRNA.activities.targets.expression))))
temporal.matrix<-as.data.frame(temporal.matrix)
colnames(temporal.matrix)<-c("PearsonCorrelation","Type")
temporal.matrix$PearsonCorrelation<-as.numeric(as.vector(temporal.matrix$PearsonCorrelation))
p <- ggplot(temporal.matrix, aes(x=Type, y=PearsonCorrelation,fill=Type)) + geom_violin()
p + stat_summary(fun.y=median, geom="point", size=2, color="purple") + ggtitle("Fig 1C")

1b. Examine the relation between the transcription of bacterial sRNAs and their regulatory activities - Part II (Fig S1)

#Create Fig S1A-E
other.ecoli.sRNAs<-c("cyaR","micA","gcvB","omrA","rybB")
#Load the output of the Inferelator
load("../Inferelator_output_files/Ecoli_8sRNAs/betas_frac_tp_100_perm_1--frac_fp_0_perm_1_1.1.RData")
load("../Inferelator_output_files/Ecoli_8sRNAs/combinedconf_frac_tp_100_perm_1--frac_fp_0_perm_1_1.1.RData")
load("../Inferelator_output_files/Ecoli_8sRNAs/params_and_input.RData")
#Extract expression response and design matrices
expression.response.matrix<-IN$final_response_matrix
expression.design.matrix<-IN$final_design_matrix
gs.matrix<-IN$gs.mat
regulators.activities.matrix<-IN$tf.activities[[1]]
par(mfrow=c(1,2))
for(i in other.ecoli.sRNAs)
{
  sRNA.activities<-regulators.activities.matrix[grep(i,rownames(regulators.activities.matrix)),]
  sRNA.transcriptional.profile<-expression.design.matrix[grep(i,rownames(expression.design.matrix)),]
  sRNA.priors<-rownames(gs.matrix)[which(gs.matrix[,grep(i,colnames(gs.matrix))]!=0)]
  sRNA.regulon.expression<-expression.response.matrix[sRNA.priors,]
  mean.expression.sRNA.regulon<-colMeans(sRNA.regulon.expression)
  plot(x=sRNA.transcriptional.profile,y=mean.expression.sRNA.regulon,col=rgb(1,0,0,1),lwd=1,xlab=paste(i,"transcription",sep=" "),ylab="Mean transcription of targets",cex=1.5, cex.lab=1.5,cex.axis=1.5)
  #Perform linear regression
  lr.sRNA.exp.regulon<-lm(mean.expression.sRNA.regulon ~ as.numeric(sRNA.transcriptional.profile))
  abline(lr.sRNA.exp.regulon,col="darkred",lwd=3,lty=2)
  plot(x=sRNA.activities,y=mean.expression.sRNA.regulon,col=rgb(1,0,0,1),lwd=1,xlab=paste(capitalize(i),"activity",sep=" "),ylab="",cex=1.5, cex.lab=1.5,cex.axis=1.5)
  #Perform linear regression
  lr.sRNA.activity.regulon<-lm(mean.expression.sRNA.regulon ~ as.numeric(sRNA.activities))
  abline(lr.sRNA.activity.regulon,col="darkred",lwd=3,lty=2)
}

#Create Fig S1F
#Load B. subtilis run
load("../Inferelator_output_files/FsrA_Bsubtilis/params_and_input.RData")
load("../Inferelator_output_files/FsrA_Bsubtilis/combinedconf_frac_tp_100_perm_1--frac_fp_0_perm_1_1.1.RData")
load("../Inferelator_output_files/FsrA_Bsubtilis/betas_frac_tp_100_perm_1--frac_fp_0_perm_1_1.1.RData")
#Extract expression response and design matrices
expression.response.matrix<-IN$final_response_matrix
expression.design.matrix<-IN$final_design_matrix
gs.matrix<-IN$gs.mat
regulators.activities.matrix<-IN$tf.activities[[1]]
FsrA<-"new_1483539_1483640"
sRNA.activities<-regulators.activities.matrix[FsrA,]
sRNA.transcriptional.profile<-expression.design.matrix[FsrA,]
sRNA.priors<-rownames(gs.matrix)[which(gs.matrix[,FsrA]!=0)]
sRNA.regulon.expression<-expression.response.matrix[sRNA.priors,]
mean.expression.sRNA.regulon<-colMeans(sRNA.regulon.expression)
plot(x=sRNA.transcriptional.profile,y=mean.expression.sRNA.regulon,col=rgb(1,0,0,1),lwd=1,xlab="fsrA transcription",ylab="Mean transcription of targets",cex=1.5, cex.lab=1.5,cex.axis=1.5, main="Fig S1F")
#Perform linear regression
lr.sRNA.exp.regulon<-lm(mean.expression.sRNA.regulon ~ as.numeric(sRNA.transcriptional.profile))
abline(lr.sRNA.exp.regulon,col="darkred",lwd=3,lty=2)
plot(x=sRNA.activities,y=mean.expression.sRNA.regulon,col=rgb(1,0,0,1),lwd=1,xlab="FsrA activity",ylab="",cex=1.5, cex.lab=1.5,cex.axis=1.5)
#Perform linear regression
lr.sRNA.activity.regulon<-lm(mean.expression.sRNA.regulon ~ as.numeric(sRNA.activities))
abline(lr.sRNA.activity.regulon,col="darkred",lwd=3,lty=2)

#Create Fig S1F
#Load S. aureus run
load("../Inferelator_output_files/RsaE_Saureus/params_and_input.RData")
load("../Inferelator_output_files/RsaE_Saureus/combinedconf_frac_tp_100_perm_1--frac_fp_0_perm_1_1.1.RData")
load("../Inferelator_output_files/RsaE_Saureus/betas_frac_tp_100_perm_1--frac_fp_0_perm_1_1.1.RData")
#Extract expression response and design matrices
expression.response.matrix<-IN$final_response_matrix
expression.design.matrix<-IN$final_design_matrix
gs.matrix<-IN$gs.mat
regulators.activities.matrix<-IN$tf.activities[[1]]
RsaE<-"new_911368_911465_1"
sRNA.activities<-regulators.activities.matrix[RsaE,]
sRNA.transcriptional.profile<-expression.design.matrix[RsaE,]
sRNA.priors<-rownames(gs.matrix)[which(gs.matrix[,RsaE]!=0)]
sRNA.regulon.expression<-expression.response.matrix[sRNA.priors,]
mean.expression.sRNA.regulon<-colMeans(sRNA.regulon.expression)
plot(x=sRNA.transcriptional.profile,y=mean.expression.sRNA.regulon,col=rgb(1,0,0,1),lwd=1,xlab="rsaE transcription",ylab="Mean transcription of targets",cex=1.5, cex.lab=1.5,cex.axis=1.5, main="Fig S1G")
#Perform linear regression
lr.sRNA.exp.regulon<-lm(mean.expression.sRNA.regulon ~ as.numeric(sRNA.transcriptional.profile))
abline(lr.sRNA.exp.regulon,col="darkred",lwd=3,lty=2)
plot(x=sRNA.activities,y=mean.expression.sRNA.regulon,col=rgb(1,0,0,1),lwd=1,xlab="RsaE activity",ylab="",cex=1.5, cex.lab=1.5,cex.axis=1.5)
#Perform linear regression
lr.sRNA.activity.regulon<-lm(mean.expression.sRNA.regulon ~ as.numeric(sRNA.activities))
abline(lr.sRNA.activity.regulon,col="darkred",lwd=3,lty=2)

2a. Evaluate performance of the Inferelator and CLR with and without sRNA activities (Fig 3A)

#Plot performance of the Inferelator with sRNA activities
#Load the output files of the Inferelator run for E. coli
load("../Inferelator_output_files/Ecoli_8sRNAs/betas_frac_tp_100_perm_1--frac_fp_0_perm_1_1.1.RData")
load("../Inferelator_output_files/Ecoli_8sRNAs/combinedconf_frac_tp_100_perm_1--frac_fp_0_perm_1_1.1.RData")
load("../Inferelator_output_files/Ecoli_8sRNAs/params_and_input.RData")
#Normalize confidence score matrix
source("../Miscellaneous_scripts/create_final_networks.R")
[1] 0.3668516
#Save the names of sRNAs to be considered in this analysis (FnrS is not included)
sRNAs<-colnames(IN$priors.mat)[140:146]
#Create matrix with normalized confidence score for selected sRNAs
normalized.confidence.matrix.sRNAs<-normalized.confidence.matrix[,sRNAs]
#Convert sRNA priors to zeroes in the normalized confidence score matrix
normalized.confidence.matrix.sRNAs[which(IN$priors.mat[,sRNAs]!=0)]<-0
#Run script to read all candidate sRNA targets supported by experimental data and genomic location (operons)
source("../Miscellaneous_scripts/sRNA_candidate_targets_compilation.R")
#Create vector to save number of supported priors at different ranking positions per sRNA 
performance.inferelator.sRNA.activity<-c()
for(y in 1:100)
{
total.supported.predictions<-0
for(s in colnames(normalized.confidence.matrix.sRNAs))
{
  candidate.targets<-unique(expanded.sRNA.gs[which(expanded.sRNA.gs[,1]== s),2])
  top.targets<-rownames(normalized.confidence.matrix.sRNAs)[order(normalized.confidence.matrix.sRNAs[,s],decreasing=T)[1:y]]
  #Keep only the loci tags
  top.targets<-translate.names(top.targets)
  total.supported.predictions <- total.supported.predictions + length(intersect(candidate.targets,top.targets))
}
performance.inferelator.sRNA.activity<-c(performance.inferelator.sRNA.activity,total.supported.predictions)
}
plot(x=1:100, y=performance.inferelator.sRNA.activity,ylim=c(0,72),xlab="Targets per sRNA",ylab="Supported predictions",col="dark green",type="lines",lwd=2,cex=1.5,cex.lab=1.5,cex.axis=1.5)
#Plot performance of CLR without sRNA activities (sRNA expression instead) using script in the folder of the Inferelator code 
source("../Inferelator_2015.08.05/R_scripts/mi_and_clr.R")
#Remove FnrS from the set of potential regulators
regulators.names<-IN$tf.names[-147]
X<-IN$final_design_matrix[regulators.names,]
#This is the same IN$final_response_matrix because we did not use a metadata file (for time series) 
Y<-IN$final_response_matrix_halftau 
#Calculate mutual information (MI) as done in the Inferelator
Ms <- mi(t(Y), t(X), nbins=PARS$mi.bins, cpu.n=PARS$cores)  
diag(Ms) <- 0
Ms_bg <- mi(t(X), t(X), nbins=PARS$mi.bins, cpu.n=PARS$cores)
diag(Ms_bg) <- 0
#Calculate CLR
clr.matrix = mixedCLR(Ms_bg,Ms)
dimnames(clr.matrix) <- list(rownames(Y), rownames(X))
#Names of sRNA to be considered in this analysis (FnrS is not included)
sRNAs<-colnames(IN$priors.mat)[140:146]
#Create matrix with normalized CLR scores for selected sRNAs
clr.matrix.sRNAs<-clr.matrix[,sRNAs]
performance.clr.sRNA.exp<-c()
for(y in 1:100)
{
total.supported.predictions<-0
for(s in colnames(clr.matrix.sRNAs))
{
  candidate.targets<-unique(expanded.sRNA.gs[which(expanded.sRNA.gs[,1]== s),2])
  top.targets<-rownames(clr.matrix.sRNAs)[order(clr.matrix.sRNAs[,s],decreasing=T)[1:y]]
  top.targets<-translate.names(top.targets)
  total.supported.predictions <- total.supported.predictions + length(intersect(candidate.targets,top.targets))
}
performance.clr.sRNA.exp<-c(performance.clr.sRNA.exp,total.supported.predictions)
}
lines(x=1:100, y=performance.clr.sRNA.exp,col="orange",lwd=2)
#Plot performance of CLR with sRNA activities
X<-IN$tf.activities[[1]]
Y<-IN$final_response_matrix_halftau
#Calculate mutual information (MI) as done in the Inferelator
Ms <- mi(t(Y), t(X), nbins=PARS$mi.bins, cpu.n=PARS$cores)  
diag(Ms) <- 0
Ms_bg <- mi(t(X), t(X), nbins=PARS$mi.bins, cpu.n=PARS$cores)
diag(Ms_bg) <- 0
#Calculate CLR
clr.matrix = mixedCLR(Ms_bg,Ms)
dimnames(clr.matrix) <- list(rownames(Y), rownames(X))
#Create matrix with normalized clr scores for selected sRNAs
clr.matrix.sRNAs<-clr.matrix[,sRNAs]
#Convert sRNA priors to zeroes in the CLR matrix
clr.matrix.sRNAs[which(IN$priors.mat[,sRNAs]!=0)]<-0
performance.clr.sRNA.act<-c()
for(y in 1:100)
{
total.supported.predictions<-0
for(s in colnames(clr.matrix.sRNAs))
{
  candidate.targets<-unique(expanded.sRNA.gs[which(expanded.sRNA.gs[,1]== s),2])
  top.targets<-rownames(clr.matrix.sRNAs)[order(clr.matrix.sRNAs[,s],decreasing=T)[1:y]]
  top.targets<-translate.names(top.targets)
  total.supported.predictions <- total.supported.predictions + length(intersect(candidate.targets,top.targets))
}
performance.clr.sRNA.act<-c(performance.clr.sRNA.act,total.supported.predictions)
}
lines(x=1:100, y=performance.clr.sRNA.act,col="blue",lwd=2)
#Plot performance of the Inferelator without sRNA activities (no TF or sRNA priors were specified)
#Load Inferelator output
load("../Inferelator_output_files/Ecoli_without_regulators_priors/betas_frac_tp_100_perm_1--frac_fp_0_perm_1_0.RData")
load("../Inferelator_output_files/Ecoli_without_regulators_priors/combinedconf_frac_tp_100_perm_1--frac_fp_0_perm_1_0.RData")
load("../Inferelator_output_files/Ecoli_without_regulators_priors/params_and_input.RData")
#Create matrix with normalized confidence score for selected sRNAs
normalized.confidence.matrix<-normalization(as.matrix(comb.confs))
normalized.confidence.matrix.sRNAs<-normalized.confidence.matrix[,sRNAs]
performance.inferelator.sRNA.exp<-c()
for(y in 1:100)
{
total.supported.predictions<-0
for(s in colnames(normalized.confidence.matrix.sRNAs))
{
  candidate.targets<-unique(expanded.sRNA.gs[which(expanded.sRNA.gs[,1]== s),2])
  top.targets<-rownames(normalized.confidence.matrix.sRNAs)[order(normalized.confidence.matrix.sRNAs[,s],decreasing=T)[1:y]]
  top.targets<-translate.names(top.targets)
  total.supported.predictions <- total.supported.predictions + length(intersect(candidate.targets,top.targets))
}
performance.inferelator.sRNA.exp<-c(performance.inferelator.sRNA.exp,total.supported.predictions)
}
lines(x=1:100, y=performance.inferelator.sRNA.exp,col="purple",lwd=2)
#Plot performance of the Inferelator with sRNA activities and shuffled sRNA priors
performance.inferelator.shuffled.sRNA.priors<-c()
for(r in 1:10)
{
  shuffled.path<-paste("../Inferelator_output_files/Ecoli_shuffled_sRNA_priors/Ecoli_shuffled_sRNA_priors",r,"/",sep="")
  #Load Inferelator output files
  load(paste(shuffled.path,"combinedconf_frac_tp_100_perm_1--frac_fp_0_perm_1_1.1.RData",sep=""))
  load(paste(shuffled.path,"params_and_input.RData",sep=""))
  load(paste(shuffled.path,"betas_frac_tp_100_perm_1--frac_fp_0_perm_1_1.1.RData",sep=""))
  #Create matrix with normalized confidence score for selected sRNAs
  normalized.confidence.matrix.shuffled.priors<-normalization(as.matrix(comb.confs))
  normalized.confidence.matrix.shuffled.priors.sRNAs<-normalized.confidence.matrix.shuffled.priors[,sRNAs]
  #Convert sRNA priors to zeroes in the normalized confidence score matrix
  normalized.confidence.matrix.shuffled.priors.sRNAs[which(IN$priors.mat[,sRNAs]!=0)]<-0
  temporal.performance<-c()
  for(y in 1:100)
  {
  total.supported.predictions<-0
  for(s in colnames(clr.matrix.sRNAs))
  {
  candidate.targets<-unique(expanded.sRNA.gs[which(expanded.sRNA.gs[,1]== s),2])
  top.targets<-rownames(normalized.confidence.matrix.shuffled.priors.sRNAs)[order(normalized.confidence.matrix.shuffled.priors.sRNAs[,s],decreasing=T)[1:y]]
  top.targets<-translate.names(top.targets)
  total.supported.predictions <- total.supported.predictions + length(intersect(candidate.targets,top.targets))
  }
  temporal.performance<-c(temporal.performance,total.supported.predictions)
  }
  performance.inferelator.shuffled.sRNA.priors<-rbind(performance.inferelator.shuffled.sRNA.priors,temporal.performance)
  }
  lines(x=1:100, y=colMeans(performance.inferelator.shuffled.sRNA.priors),col="dark grey",lwd=2)
  legend("topleft",inset=0.03,box.lty=0.1,box.lwd=0.2,c("BBSR.SRA","BBSR.SRA.Shuffled","BBSR","CLR.SRA","CLR"),col=c("dark green","dark grey","purple","blue","orange"),cex=0.65,lty=1,lwd=2)

2b. Visually inspect the infered E.coli sRNA network. Fig 3B was created in Cytoscape. Here we use the igraph package to get a raw draft.

#Load the output files of the Inferelator run for E. coli
load("../Inferelator_output_files/Ecoli_8sRNAs/betas_frac_tp_100_perm_1--frac_fp_0_perm_1_1.1.RData")
load("../Inferelator_output_files/Ecoli_8sRNAs/combinedconf_frac_tp_100_perm_1--frac_fp_0_perm_1_1.1.RData")
load("../Inferelator_output_files/Ecoli_8sRNAs/params_and_input.RData")
#Create final network model
source("../Miscellaneous_scripts/create_final_networks.R")
[1] 0.3668516
#Create table with sRNA-mRNA interactions for all eight sRNAs
sRNAs<-colnames(IN$priors.mat)[140:147]
#Function to remove the loci part of gene IDs used in expression, confidence score and betas matrices
remove.locus.tag<-function(geneNames)
{
  output<-sapply(1:length(geneNames),function(x){strsplit(as.character(geneNames)[x],split = "_")[[1]][1]})
  output
}
#Function to create the sRNA network - it uses final network model created above
create.network<-function(regulatorsNames,recoveredInteractionsMatrix,novelInteractionsMatrix,betas)
{
output.network<-c()
for(g in regulatorsNames)
{
  recovered.targets<-names(which(recoveredInteractionsMatrix[,g]!=0))
  novel.targets<-names(which(novelInteractionsMatrix[,g]!=0))
  g<-remove.locus.tag(g)
  if(length(recovered.targets)>0)
  {
  
  output.network<-rbind(output.network,cbind(rep(g,length(recovered.targets)),remove.locus.tag(recovered.targets)
                                         ,rep("prior",length(recovered.targets))))
  }
  if(length(novel.targets)>0)
  {
  output.network<-rbind(output.network,cbind(rep(g,length(novel.targets)),remove.locus.tag(novel.targets)
                                         ,rep("novel",length(novel.targets))))
  }
}
colnames(output.network)<-c("Regulator","Target","Interaction")
output.network
}
sRNAs.network<-create.network(sRNAs,recovered.interactions.matrix,novel.interactions.matrix)
sRNA.network.igraph.format<-graph_from_data_frame(sRNAs.network[,c("Regulator","Target")]
                                                  ,union(sRNAs.network[,"Regulator"],sRNAs.network[,"Target"]), directed = T)
selected.network.layout <- layout_nicely(sRNA.network.igraph.format)
plot(sRNA.network.igraph.format,layout = selected.network.layout, edge.arrow.size =0.2,vertex.label.cex=0.3,vertex.size=9,main="Fig 3B draft")

2c. Compare the regression coefficients (betas) of sRNA-mRNA and TF-gene interactions (Fig 3C)

betas.tfs<-c()
betas.sRNAs<-c()
#Save TFs names
TFs<-setdiff(colnames(normalized.confidence.matrix),sRNAs)
#Combined recovered and novel interactions in a single matrix
all.predictions.matrix<-recovered.interactions.matrix + novel.interactions.matrix
betas.tfs<-abs(combined.betas[,TFs][which(all.predictions.matrix[,TFs]!=0)])
betas.sRNAs<-abs(combined.betas[,sRNAs][which(all.predictions.matrix[,sRNAs]!=0)])
temporal.matrix<-rbind(cbind(betas.tfs,rep("TFs",length(betas.tfs))),cbind(betas.sRNAs,rep("sRNAs",length(betas.sRNAs))))
colnames(temporal.matrix)<-c("Betas","Type")
temporal.matrix<-as.data.frame(temporal.matrix)
temporal.matrix$Betas<-as.numeric(as.vector(temporal.matrix$Betas))
p <- ggplot(temporal.matrix, aes(x=Type, y=Betas,fill=Type)) + geom_violin(show.legend = F)
p + stat_summary(fun.y=median, geom="point", size=2,show.legend = F) + coord_flip()

2d. Plot experimental support of the inferred E. coli sRNA regulons (Fig 3D)

#This figure is generated using data in Supplementary Dataset 1
accuracy.sRNA.regulons<-c()
accuracy.CyaR.regulon<-cbind(c(6,1,7,0),c(0,4,4,0)) 
accuracy.sRNA.regulons<-rbind(accuracy.sRNA.regulons,accuracy.CyaR.regulon)
accuracy.FnrS.regulon<-cbind(c(7,1,8,0),c(0,6,6,0))
accuracy.sRNA.regulons<-rbind(accuracy.sRNA.regulons,accuracy.FnrS.regulon)
accuracy.GcvB.regulon<-cbind(c(6,16,22,0),c(0,11,11,0))
accuracy.sRNA.regulons<-rbind(accuracy.sRNA.regulons,accuracy.GcvB.regulon)
accuracy.OmrA.regulon<-cbind(c(4,1,5,0),c(0,0,0,0))
accuracy.sRNA.regulons<-rbind(accuracy.sRNA.regulons,accuracy.OmrA.regulon)
accuracy.RybB.regulon<-cbind(c(5,0,5,0),c(0,3,3,0))
accuracy.sRNA.regulons<-rbind(accuracy.sRNA.regulons,accuracy.RybB.regulon)
accuracy.RyhB.regulon<-cbind(c(6,5,11,0),c(0,8,8,0))
accuracy.sRNA.regulons<-rbind(accuracy.sRNA.regulons,accuracy.RyhB.regulon)
accuracy.Spot42.regulon<-cbind(c(4,5,9,0),c(0,0,0,0))
accuracy.sRNA.regulons<-rbind(accuracy.sRNA.regulons,accuracy.Spot42.regulon)
#Create barplot
barplot(t(accuracy.sRNA.regulons),col=rep(c(rgb(90,180,172,maxColorValue = 255),rgb(216,179,101,maxColorValue = 255)),28)
        ,names=rep(c("Known","Novel","Full",""),7),las=2,cex.axis = 1.25,ylab="# Targets")
legend("topleft", 
       legend = c("Supported", "Not Supported"), 
       fill = c(rgb(90,180,172,maxColorValue = 255),rgb(216,179,101,maxColorValue = 255)),bty="n")

2e. Plot performance of the Inferelator with noisy sRNA priors (Fig 3E & Fig S2)

#Load Inferelator run without noisy sRNA priors
load("../Inferelator_output_files/Ecoli_8sRNAs/betas_frac_tp_100_perm_1--frac_fp_0_perm_1_1.1.RData")
load("../Inferelator_output_files/Ecoli_8sRNAs/combinedconf_frac_tp_100_perm_1--frac_fp_0_perm_1_1.1.RData")
load("../Inferelator_output_files/Ecoli_8sRNAs/params_and_input.RData")
#Create final model
source("../Miscellaneous_scripts/create_final_networks.R")
[1] 0.3668516
#Save manually selected sRNA priors used as input for the Inferelator
original.sRNAs.gs<-IN$priors.mat[,sRNAs]
#Recovered sRNA priors in the Inferelator run without noisy priors
recovered.sRNA.priors.no.noise<-recovered.interactions.matrix[,sRNAs]
#The ratio of true:false ratio in the noisy sRNA priors (1:1,1:2,1:5)
noise.level<-c(1,2,5)
#Create matrix to store average experimental support rate of recovered sRNA priors
mean.support.rate.recovered.priors.matrix<-matrix(nrow=3,ncol=length(sRNAs)+1,0,dimnames = list(paste("n",noise.level,sep=""),c(sRNAs,"Random")))
#The expected average ratio from  random selections
mean.support.rate.recovered.priors.matrix[,9]<-c(1/2,1/3,1/6)
#Create matrix to store average number of recovered sRNA priors
mean.number.recovered.priors<-matrix(nrow=3,ncol=length(sRNAs),0,dimnames = list(paste("n",noise.level,sep=""),sRNAs))
#Create matrix to store average number of experimentally supported recovered sRNA priors
mean.number.true.recovered.priors<-matrix(nrow=3,ncol=length(sRNAs),0,dimnames = list(paste("n",noise.level,sep=""),sRNAs))
#This loop computes the number of recovered priors and the exp. support rate of the recovered priors for the Inferelator runs that used noisy sRNA priors (ten runs for each noise level)  
for(k in noise.level)
{
  #Create matrices to store the information of the ten Inferelator runs 
  temporal.recovered.sRNA.priors.matrix<-matrix(nrow=10,ncol=length(sRNAs),0,dimnames = list(paste("r",1:10,sep=""),sRNAs))
  temporal.recovered.true.sRNA.priors.matrix<-matrix(nrow=10,ncol=length(sRNAs),0,dimnames = list(paste("r",1:10,sep=""),sRNAs))
  temporal.suppport.rate.recovered.sRNA.priors.matrix<-matrix(nrow=10,ncol=length(sRNAs),0,dimnames = list(paste("r",1:10,sep=""),sRNAs))
  
  for(r in 1:10)
  {
  path.to.noisy.inferelator.output<-"../Inferelator_output_files/Ecoli_noisy_sRNA_priors/eco_sRNA_strong_m3F_unaveraged_noisyPriors_n"
  load(paste(path.to.noisy.inferelator.output,k,"_r",r,"/combinedconf_frac_tp_100_perm_1--frac_fp_0_perm_1_1.1.RData",sep=""))
  load(paste(path.to.noisy.inferelator.output,k,"_r",r,"/betas_frac_tp_100_perm_1--frac_fp_0_perm_1_1.1.RData",sep=""))
  load(paste(path.to.noisy.inferelator.output,k,"_r",r,"/params_and_input.RData",sep=""))
  source("../Miscellaneous_scripts/create_final_networks.R")
  for(s in sRNAs)
  {
    true.sRNA.priors<-names(which(original.sRNAs.gs[,s]!=0))
    #The curated.gs.matrix object was created by the create_final_networks.R script used above
    noisy.sRNA.priors<-names(which(curated.gs.matrix[,s]!=0))
    #The recovered.sRNA.priors object was created by the create_final_networks.R script used above
    recovered.sRNA.priors<-names(which(recovered.interactions.matrix[,s]!=0))
    temporal.recovered.sRNA.priors.matrix[paste("r",r,sep=""),s]<-length(recovered.sRNA.priors)
    temporal.recovered.true.sRNA.priors.matrix[paste("r",r,sep=""),s]<-length(intersect(recovered.sRNA.priors,true.sRNA.priors))
    temporal.suppport.rate.recovered.sRNA.priors.matrix[paste("r",r,sep=""),s]<-temporal.recovered.true.sRNA.priors.matrix[paste("r",r,sep=""),s]/length(recovered.sRNA.priors)
  }
  }
  #Compute average acrros the ten runs
  mean.number.recovered.priors[paste("n",k,sep=""),1:8]<-colMeans(temporal.recovered.sRNA.priors.matrix,na.rm = T)
  mean.number.true.recovered.priors[paste("n",k,sep=""),1:8]<-colMeans(temporal.recovered.true.sRNA.priors.matrix,na.rm=T)
  mean.support.rate.recovered.priors.matrix[paste("n",k,sep=""),1:8]<-colMeans(temporal.suppport.rate.recovered.sRNA.priors.matrix,na.rm=T)
}
[1] 0.3483171
[1] 0.3581108
[1] 0.3528762
[1] 0.3535159
[1] 0.3515724
[1] 0.3514696
[1] 0.3531012
[1] 0.3540409
[1] 0.3500886
[1] 0.3556734
[1] 0.3395171
[1] 0.3387281
[1] 0.3421028
[1] 0.3356091
[1] 0.3393354
[1] 0.3403037
[1] 0.3419162
[1] 0.3375457
[1] 0.3405978
[1] 0.3380823
[1] 0.3158115
[1] 0.3157688
[1] 0.3167973
[1] 0.3146657
[1] 0.3164843
[1] 0.3163847
[1] 0.3151067
[1] 0.3167479
[1] 0.3141667
[1] 0.3186626
par(mfrow=c(1,1))
boxplot(ylim=c(0,1),t(mean.support.rate.recovered.priors.matrix),col="white",outline=F,boxlty=0,whisklty = 0, staplelty = 0, names=c("1:1","1:2","1:5"),frame=F,
  xlab="Supported : Unsupported priors",ylab="Proportion of recovered priors w/ support",cex.lab=1.1,main="Fig 3E")
dots.colors<-c("blue","red","dark green","deeppink","orange","cyan","purple","brown","gray")
dots.shapes<-c(2,1,3:6,0,7,8)
for(r in 1:(length(sRNAs)+1))
{
 points(y=mean.support.rate.recovered.priors.matrix[,r],x=c(1,2,3),pch=dots.shapes[r],col=dots.colors[r])
}
legend("bottomleft",inset=0.03,box.lty=0.1,box.lwd=0.2,
  c("RyhB(12)","Spot42(12)","GcvB(9)","MicA(10)","OmrA(6)","CyaR(6)","RybB(10)","FnrS(10)","Random"),col=dots.colors,cex=0.65,pch=dots.shapes)
#Create Fig S2 (because MicA targets were not predicted in the original run- we remove MicA from the following analysis)
sRNAs.figS2<-sRNAs[-4]
par(mfrow=c(1,2))

#Panel A
boxplot(ylim=c(0,1.2),t(mean.number.recovered.priors[,sRNAs.figS2])/colSums(abs(recovered.sRNA.priors.no.noise[,sRNAs.figS2])),col="white",outline=F,boxlty=0,whisklty = 0, staplelty = 0, names=c("1:1","1:2","1:5"),frame=F,xlab="Supported : Unsupported priors",ylab="Total recovered priors (compared to run w/out false priors)",cex.lab=1.1,main="Fig S2A")
for(x in 1:(length(sRNAs.figS2)))
{
 points(y=mean.number.recovered.priors[,sRNAs.figS2[x]]/sum(abs(recovered.sRNA.priors.no.noise[,sRNAs.figS2[x]])),x=c(1,2,3),pch=dots.shapes[-4][x],col=dots.colors[-4][x])
}
#Panel B
boxplot(ylim=c(0,1.2),t(mean.number.true.recovered.priors[,sRNAs.figS2])/colSums(abs(recovered.sRNA.priors.no.noise[,sRNAs.figS2])),col="white",outline=F,boxlty=0,whisklty = 0, staplelty = 0, names=c("1:1","1:2","1:5"),frame=F,xlab="Supported : Unsupported priors",ylab="True recovered priors (compared to no false priors run)",cex.lab=1.1,main="Fig S2B")
for(x in 1:(length(sRNAs.figS2)))
{
 points(y=mean.number.true.recovered.priors[,sRNAs.figS2[x]]/sum(abs(recovered.sRNA.priors.no.noise[,sRNAs.figS2[x]])),x=c(1,2,3),pch=dots.shapes[-4][x],col=dots.colors[-4][x])
}
legend("topright",inset=0.03,box.lty=0.1,box.lwd=0.2,
  c("RyhB(12)","Spot42(12)","GcvB(9)","OmrA(6)","CyaR(6)","RybB(10)","FnrS(10)"),cex=0.65,pch=dots.shapes[1:8][-4],col=dots.colors[1:8][-4])

  1. Inspect sRNA regulons inferred using CopraRNA (Wrigth et al. 2013) sRNA priors (Fig 4)
#Create Fig 4B using Table S2
copraRNA.100.support.rate<-c(.29,.3,.17)
copraRNA.100.recovered.priors.support.rate<-c(1,.67,.33)
copraRNA.pval.support.rate<-c(.35,.46,.22)
copraRNA.pval.recovered.priors.support.rate<-c(.4,.82,.25)
copraRNA.enriched.support.rate<-c(.5,.56,.26)
copraRNA.enriched.recovered.priors.support.rate<-c(1,.82,.4)
copraRNA.top15.support.rate<-c(.48,.64,.31)
copraRNA.top15.recovered.priors.support.rate<-c(1,.8,.5)
copraRNA.AND.support.rate<-c(.55,.73,.35)
copraRNA.AND.recovered.priors.support.rate<-c(1,.77,.67)
copraRNA.OR.support.rate<-c(.37,.41,.2)
copraRNA.OR.recovered.priors.support.rate<-c(1,.8,.29)
copraRNA.support.rate<-c(copraRNA.100.support.rate,copraRNA.pval.support.rate,copraRNA.enriched.support.rate,
                         copraRNA.top15.support.rate,copraRNA.AND.support.rate,copraRNA.OR.support.rate)
copraRNA.recovered.priors.support.rate<-c(copraRNA.100.recovered.priors.support.rate,copraRNA.pval.recovered.priors.support.rate,
                                          copraRNA.enriched.recovered.priors.support.rate,copraRNA.top15.recovered.priors.support.rate,
                                          copraRNA.AND.recovered.priors.support.rate,copraRNA.OR.recovered.priors.support.rate)

plot(x=copraRNA.support.rate,y=copraRNA.recovered.priors.support.rate,col=rep(c("purple","green","orange"),6),xlab="Experimental support rate - CopraRNA priors",ylab="Experimental support rate - Recovered priors",xlim=c(0,1),ylim=c(0,1),
     pch=rep(c(15,16,17,18,19,4),each=3))
lines(x=c(0,1),y=c(0,1),col="red",lty=2)
legend('bottomright', c("RyhB","GcvB","Spot 42"), col=c("purple","green","orange"),pch=16,bty="n")

#Plot the inferred RyhB regulon when CopraRNA predictions associated with enriched functional terms were used as priors (Fig 4C)
#Here we use the igraph package to get  raw drafts
#Load the output files of the corresponding Inferelator run
load("../Inferelator_output_files/Ecoli_CopraRNA_sRNA_priors/ryhB_silico_2_BBSR_1.1_100_0/betas_frac_tp_100_perm_1--frac_fp_0_perm_1_1.1.RData")
load("../Inferelator_output_files/Ecoli_CopraRNA_sRNA_priors/ryhB_silico_2_BBSR_1.1_100_0/combinedconf_frac_tp_100_perm_1--frac_fp_0_perm_1_1.1.RData")
load("../Inferelator_output_files/Ecoli_CopraRNA_sRNA_priors/ryhB_silico_2_BBSR_1.1_100_0/params_and_input.RData")
#Create final network model
source("../Miscellaneous_scripts/create_final_networks.R")
[1] 0.3583497
#Save the inferred RyhB regulon
RyhB.regulon<-create.network("ryhB_b4451_4",recovered.interactions.matrix,novel.interactions.matrix)
RyhB.regulon.igraph.format<-graph_from_data_frame(RyhB.regulon[,1:2], union(RyhB.regulon[,"Regulator"],RyhB.regulon[,"Target"]), directed = T)
plot(RyhB.regulon.igraph.format,layout = layout_nicely(RyhB.regulon.igraph.format), edge.arrow.size =0.4,vertex.label.cex=1,vertex.size=30,main="Fig 4C",vertex.shape=c("square",rep("circle",nrow(RyhB.regulon))),vertex.label.color=c("blue",rep("black",length(grep("prior",RyhB.regulon[,3]))),rep("white",length(grep("novel",RyhB.regulon[,3])))))

#Plot the inferred GcvB regulon when CopraRNA predictions with p-value <= 0.01 were used as priors (Fig 4D)
#Load the output files of the corresponding Inferelator run
load("../Inferelator_output_files/Ecoli_CopraRNA_sRNA_priors/gcvB_silico_1_BBSR_1.1_100_0/betas_frac_tp_100_perm_1--frac_fp_0_perm_1_1.1.RData")
load("../Inferelator_output_files/Ecoli_CopraRNA_sRNA_priors/gcvB_silico_1_BBSR_1.1_100_0/combinedconf_frac_tp_100_perm_1--frac_fp_0_perm_1_1.1.RData")
load("../Inferelator_output_files/Ecoli_CopraRNA_sRNA_priors/gcvB_silico_1_BBSR_1.1_100_0/params_and_input.RData")
#Create final network model
source("../Miscellaneous_scripts/create_final_networks.R")
[1] 0.3591327
#Save the inferred GcvB regulon
GcvB.regulon<-create.network("gcvB_b4443_12",recovered.interactions.matrix,novel.interactions.matrix)
GcvB.regulon.igraph.format<-graph_from_data_frame(GcvB.regulon[,1:2], union(GcvB.regulon[,"Regulator"],GcvB.regulon[,"Target"]), directed = T)
plot(GcvB.regulon.igraph.format,layout = layout_nicely(GcvB.regulon.igraph.format), edge.arrow.size =0.4,vertex.label.cex=0.8,vertex.size=21,main="Fig 4D",vertex.shape=c("square",rep("circle",nrow(GcvB.regulon))),vertex.label.color=c("blue",rep("black",length(grep("prior",GcvB.regulon[,3]))),rep("white",length(grep("novel",GcvB.regulon[,3])))))

#Plot the inferred Spot 42 regulon when CopraRNA predictions with p-value <= 0.01 & associated with enriched functional terms were used as priors (Fig 4E)
#Load the output files of the corresponding Inferelator run
load("../Inferelator_output_files/Ecoli_CopraRNA_sRNA_priors/spf_silico_3_BBSR_1.1_100_0/betas_frac_tp_100_perm_1--frac_fp_0_perm_1_1.1.RData")
load("../Inferelator_output_files/Ecoli_CopraRNA_sRNA_priors/spf_silico_3_BBSR_1.1_100_0/combinedconf_frac_tp_100_perm_1--frac_fp_0_perm_1_1.1.RData")
load("../Inferelator_output_files/Ecoli_CopraRNA_sRNA_priors/spf_silico_3_BBSR_1.1_100_0/params_and_input.RData")
#Create final network model
source("../Miscellaneous_scripts/create_final_networks.R")
[1] 0.3607158
#Save the inferred Spot 42 regulon
Spot42.regulon<-create.network("spf_b3864_15",recovered.interactions.matrix,novel.interactions.matrix)
Spot42.regulon.igraph.format<-graph_from_data_frame(Spot42.regulon[,1:2], union(Spot42.regulon[,"Regulator"],Spot42.regulon[,"Target"]), directed = T)
plot(Spot42.regulon.igraph.format,layout = layout_nicely(Spot42.regulon.igraph.format), edge.arrow.size =0.4,vertex.label.cex=0.8,vertex.size=30,main="Fig 4E",vertex.shape=c("square",rep("circle",nrow(Spot42.regulon))),vertex.label.color=c("blue",rep("black",length(grep("prior",Spot42.regulon[,3]))),rep("white",length(grep("novel",Spot42.regulon[,3])))))

  1. Create sRNA regulons shown in Fig 5. This figure was created in Cytoscape. Here we use the igraph package to get raw drafts.
#Load the output files of the Inferelator run for E. coli
load("../Inferelator_output_files/Ecoli_8sRNAs/betas_frac_tp_100_perm_1--frac_fp_0_perm_1_1.1.RData")
load("../Inferelator_output_files/Ecoli_8sRNAs/combinedconf_frac_tp_100_perm_1--frac_fp_0_perm_1_1.1.RData")
load("../Inferelator_output_files/Ecoli_8sRNAs/params_and_input.RData")
#Create final network model
source("../Miscellaneous_scripts/create_final_networks.R")
[1] 0.3668516
#Create table with sRNA-mRNA interactions for all eight sRNAs
sRNAs<-colnames(IN$priors.mat)[140:147]
sRNAs.network<-create.network(sRNAs,recovered.interactions.matrix,novel.interactions.matrix)
#Plot the inferred Spot 42 regulon
Spot42.regulon<-sRNAs.network[grep("spf",sRNAs.network[,1]),]
Spot42.regulon.igraph.format<-graph_from_data_frame(Spot42.regulon[,1:2], union(Spot42.regulon[,"Regulator"],Spot42.regulon[,"Target"]), directed = T)
plot(Spot42.regulon.igraph.format,layout = layout_nicely(Spot42.regulon.igraph.format), edge.arrow.size =0.4,vertex.label.cex=1,vertex.size=30,main="Fig 5A",vertex.shape=c("square",rep("circle",nrow(Spot42.regulon))),vertex.label.color=c("blue",rep("black",length(grep("prior",Spot42.regulon[,3]))),rep("white",length(grep("novel",Spot42.regulon[,3])))))

#Plot the inferred GcvB regulon
GcvB.regulon<-sRNAs.network[grep("gcvB",sRNAs.network[,1]),]
GcvB.regulon.igraph.format<-graph_from_data_frame(GcvB.regulon[,1:2], union(GcvB.regulon[,"Regulator"],GcvB.regulon[,"Target"]), directed = T)
plot(GcvB.regulon.igraph.format,layout = layout_nicely(GcvB.regulon.igraph.format), edge.arrow.size =0.4,vertex.label.cex=1,vertex.size=30,main="Fig 5B",vertex.shape=c("square",rep("circle",nrow(GcvB.regulon))),vertex.label.color=c("blue",rep("black",length(grep("prior",GcvB.regulon[,3]))),rep("white",length(grep("novel",GcvB.regulon[,3])))))

#Plot the inferred PrrF regulon in P. aeruginosa
#Load the output files of the Inferelator run for P. aeruginosa
load("../Inferelator_output_files/PrrF_Paeruginosa/betas_frac_tp_100_perm_1--frac_fp_0_perm_1_1.1.RData")
load("../Inferelator_output_files/PrrF_Paeruginosa/combinedconf_frac_tp_100_perm_1--frac_fp_0_perm_1_1.1.RData")
load("../Inferelator_output_files/PrrF_Paeruginosa/params_and_input.RData")
#Create final network model
source("../Miscellaneous_scripts/create_final_networks.R")
[1] 0.265658
#Create table with PrrF-mRNA interactions 
PrrF.regulon<-create.network("PrrF",recovered.interactions.matrix,novel.interactions.matrix)
PrrF.regulon.igraph.format<-graph_from_data_frame(PrrF.regulon[,1:2], union(PrrF.regulon[,"Regulator"],PrrF.regulon[,"Target"]), directed = T)
plot(PrrF.regulon.igraph.format,layout = layout_nicely(PrrF.regulon.igraph.format), edge.arrow.size =0.4,vertex.label.cex=0.65,vertex.size=30,main="Fig 5C",vertex.shape=c("square",rep("circle",nrow(PrrF.regulon))),vertex.label.color=c("blue",rep("black",length(grep("prior",PrrF.regulon[,3]))),rep("white",length(grep("novel",PrrF.regulon[,3])))))

#Plot the inferred FsrA regulon in B. subtilis
#Load the output files of the Inferelator run for B. subtilis
load("../Inferelator_output_files/FsrA_Bsubtilis/betas_frac_tp_100_perm_1--frac_fp_0_perm_1_1.1.RData")
load("../Inferelator_output_files/FsrA_Bsubtilis/combinedconf_frac_tp_100_perm_1--frac_fp_0_perm_1_1.1.RData")
load("../Inferelator_output_files/FsrA_Bsubtilis/params_and_input.RData")
#Create final network model
source("../Miscellaneous_scripts/create_final_networks.R")
[1] 0.7639555
#Create table with PrrF-mRNA interactions 
FsrA.regulon<-create.network(FsrA,recovered.interactions.matrix,novel.interactions.matrix)
#Replace locus ID with common sRNA name
FsrA.regulon[,1]<-"FsrA"
FsrA.regulon.igraph.format<-graph_from_data_frame(FsrA.regulon[,1:2], union(FsrA.regulon[,"Regulator"],FsrA.regulon[,"Target"]), directed = T)
plot(FsrA.regulon.igraph.format,layout = layout_nicely(FsrA.regulon.igraph.format), edge.arrow.size =0.4,vertex.label.cex=0.55,vertex.size=32,main="Fig 5D",vertex.shape=c("square",rep("circle",nrow(FsrA.regulon))),vertex.label.color=c("blue",rep("black",length(grep("prior",FsrA.regulon[,3]))),rep("white",length(grep("novel",FsrA.regulon[,3])))))

#Plot the inferred RsaE regulon in S. aureus
#Load the output files of the Inferelator run for S. aures
load("../Inferelator_output_files/RsaE_Saureus/betas_frac_tp_100_perm_1--frac_fp_0_perm_1_1.1.RData")
load("../Inferelator_output_files/RsaE_Saureus/combinedconf_frac_tp_100_perm_1--frac_fp_0_perm_1_1.1.RData")
load("../Inferelator_output_files/RsaE_Saureus/params_and_input.RData")
#Create final network model
source("../Miscellaneous_scripts/create_final_networks.R")
[1] 0.5834941
#Create table with RsaE-mRNA interactions 
RsaE.recovered.targets<-names(which(recovered.interactions.matrix[,RsaE]!=0))
RsaE.recovered.targets<-sapply(1:length(RsaE.recovered.targets), function(x){gsub("SAOUHSC","SA",RsaE.recovered.targets[x])})
RsaE.novel.targets<-names(which(novel.interactions.matrix[,RsaE]!=0))
RsaE.novel.targets<-sapply(1:length(RsaE.novel.targets), function(x){gsub("SAOUHSC","SA",RsaE.novel.targets[x])})
RsaE.regulon<-rbind(cbind(rep("RsaE",length(RsaE.recovered.targets)),RsaE.recovered.targets,rep("priors",length(RsaE.recovered.targets))),cbind(rep("RsaE",length(RsaE.novel.targets)),RsaE.novel.targets,rep("novel",length(RsaE.novel.targets))))
colnames(RsaE.regulon)<-c("Regulator","Target","Interaction")
RsaE.regulon.igraph.format<-graph_from_data_frame(RsaE.regulon[,1:2], union(RsaE.regulon[,"Regulator"],RsaE.regulon[,"Target"]), directed = T)
plot(RsaE.regulon.igraph.format,layout = layout_nicely(RsaE.regulon.igraph.format), edge.arrow.size =0.4,vertex.label.cex=0.55,vertex.size=32,main="Fig 5E",vertex.shape=c("square",rep("circle",nrow(RsaE.regulon))),vertex.label.color=c("blue",rep("black",length(grep("prior",RsaE.regulon[,3]))),rep("white",length(grep("novel",RsaE.regulon[,3])))))

LS0tCnRpdGxlOiAiQ29tcHV0YXRpb25hbCBhbmFseXNlcyBmb3IgKkluZmVyZW5jZSBvZiBiYWN0ZXJpYWwgc21hbGwgUk5BIHJlZ3VsYXRvcnkgbmV0d29ya3MgYW5kIGludGVncmF0aW9uIHdpdGggdHJhbnNjcmlwdGlvbiBmYWN0b3IgZHJpdmVuIHJlZ3VsYXRvcnkgbmV0d29ya3MqIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKYXV0aG9yOiBNYXJpbyBBcnJpZXRhLU9ydGl6CmRhdGU6IE5vdmVtYmVyIDI0LCAyMDE5Ci0tLQowLiBMb2FkIHJlcXVpcmVkIGxpYnJhcmllcwpgYGB7ciBtZXNzYWdlPUZBTFNFfQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoSG1pc2MpCmxpYnJhcnkobXVsdHRlc3QpCmxpYnJhcnkobmV0d29yaykKbGlicmFyeShpZ3JhcGgpCmBgYAoxYS4gRXhhbWluZSB0aGUgcmVsYXRpb24gYmV0d2VlbiB0aGUgdHJhbnNjcmlwdGlvbiBvZiBiYWN0ZXJpYWwgc1JOQXMgYW5kIHRoZWlyIHJlZ3VsYXRvcnkgYWN0aXZpdGllcyAtIFBhcnQgSSAoRmlnIDEpCmBgYHtyfQojTmFtZSBvZiBzUk5BcyBzaG93biBpbiBGaWcgMSBBLUIKZmlnMS5zUk5BczwtYygic3BmIiwicnloQiIpCiNMb2FkIHRoZSBvdXRwdXQgb2YgdGhlIEluZmVyZWxhdG9yIHJ1bgpsb2FkKCIuLi9JbmZlcmVsYXRvcl9vdXRwdXRfZmlsZXMvRWNvbGlfOHNSTkFzL2JldGFzX2ZyYWNfdHBfMTAwX3Blcm1fMS0tZnJhY19mcF8wX3Blcm1fMV8xLjEuUkRhdGEiKQpsb2FkKCIuLi9JbmZlcmVsYXRvcl9vdXRwdXRfZmlsZXMvRWNvbGlfOHNSTkFzL2NvbWJpbmVkY29uZl9mcmFjX3RwXzEwMF9wZXJtXzEtLWZyYWNfZnBfMF9wZXJtXzFfMS4xLlJEYXRhIikKbG9hZCgiLi4vSW5mZXJlbGF0b3Jfb3V0cHV0X2ZpbGVzL0Vjb2xpXzhzUk5Bcy9wYXJhbXNfYW5kX2lucHV0LlJEYXRhIikKI0V4dHJhY3QgZXhwcmVzc2lvbiByZXNwb25zZSBhbmQgZGVzaWduIG1hdHJpY2VzCmV4cHJlc3Npb24ucmVzcG9uc2UubWF0cml4PC1JTiRmaW5hbF9yZXNwb25zZV9tYXRyaXgKZXhwcmVzc2lvbi5kZXNpZ24ubWF0cml4PC1JTiRmaW5hbF9kZXNpZ25fbWF0cml4CiNUaGlzIGlzIHRoZSBnb2xkIHN0YW5kYXJkIChwcmlvcikgbmV0d29yawpncy5tYXRyaXg8LUlOJGdzLm1hdAojTWF0cml4IHdpdGggcmVndWxhdG9ycyAoVEZzICYgc1JOQXMpIGFjdGl2aXRpZXMKcmVndWxhdG9ycy5hY3Rpdml0aWVzLm1hdHJpeDwtSU4kdGYuYWN0aXZpdGllc1tbMV1dCnBhcihtZnJvdz1jKDEsMikpCmZvcihpIGluIGZpZzEuc1JOQXMpCnsKICBzUk5BLmFjdGl2aXRpZXM8LXJlZ3VsYXRvcnMuYWN0aXZpdGllcy5tYXRyaXhbZ3JlcChpLHJvd25hbWVzKHJlZ3VsYXRvcnMuYWN0aXZpdGllcy5tYXRyaXgpKSxdCiAgc1JOQS50cmFuc2NyaXB0aW9uYWwucHJvZmlsZTwtZXhwcmVzc2lvbi5kZXNpZ24ubWF0cml4W2dyZXAoaSxyb3duYW1lcyhleHByZXNzaW9uLmRlc2lnbi5tYXRyaXgpKSxdCiAgc1JOQS5wcmlvcnM8LXJvd25hbWVzKGdzLm1hdHJpeClbd2hpY2goZ3MubWF0cml4WyxncmVwKGksY29sbmFtZXMoZ3MubWF0cml4KSldIT0wKV0KICBzUk5BLnJlZ3Vsb24uZXhwcmVzc2lvbjwtZXhwcmVzc2lvbi5yZXNwb25zZS5tYXRyaXhbc1JOQS5wcmlvcnMsXQogIG1lYW4uZXhwcmVzc2lvbi5zUk5BLnJlZ3Vsb248LWNvbE1lYW5zKHNSTkEucmVndWxvbi5leHByZXNzaW9uKQogIHBsb3QoeD1zUk5BLnRyYW5zY3JpcHRpb25hbC5wcm9maWxlLHk9bWVhbi5leHByZXNzaW9uLnNSTkEucmVndWxvbixjb2w9cmdiKDEsMCwwLDEpLGx3ZD0xLHhsYWI9cGFzdGUoaSwidHJhbnNjcmlwdGlvbiIsc2VwPSIgIikseWxhYj0iTWVhbiB0cmFuc2NyaXB0aW9uIG9mIHRhcmdldHMiLGNleD0xLjUsIGNleC5sYWI9MS41LGNleC5heGlzPTEuNSkKICAjUGVyZm9ybSBsaW5lYXIgcmVncmVzc2lvbgogIGxyLnNSTkEuZXhwLnJlZ3Vsb248LWxtKG1lYW4uZXhwcmVzc2lvbi5zUk5BLnJlZ3Vsb24gfiBhcy5udW1lcmljKHNSTkEudHJhbnNjcmlwdGlvbmFsLnByb2ZpbGUpKQogIGFibGluZShsci5zUk5BLmV4cC5yZWd1bG9uLGNvbD0iZGFya3JlZCIsbHdkPTMsbHR5PTIpCiAgcGxvdCh4PXNSTkEuYWN0aXZpdGllcyx5PW1lYW4uZXhwcmVzc2lvbi5zUk5BLnJlZ3Vsb24sY29sPXJnYigxLDAsMCwxKSxsd2Q9MSx4bGFiPXBhc3RlKGNhcGl0YWxpemUoaSksImFjdGl2aXR5IixzZXA9IiAiKSx5bGFiPSIiLGNleD0xLjUsIGNleC5sYWI9MS41LGNleC5heGlzPTEuNSkKICAjUGVyZm9ybSBsaW5lYXIgcmVncmVzc2lvbgogIGxyLnNSTkEuYWN0aXZpdHkucmVndWxvbjwtbG0obWVhbi5leHByZXNzaW9uLnNSTkEucmVndWxvbiB+IGFzLm51bWVyaWMoc1JOQS5hY3Rpdml0aWVzKSkKICBhYmxpbmUobHIuc1JOQS5hY3Rpdml0eS5yZWd1bG9uLGNvbD0iZGFya3JlZCIsbHdkPTMsbHR5PTIpCn0KI0NyZWF0ZSBzaW1pbGFyIGZpZ3VyZSBmb3IgRm5yUyBhY3Rpdml0eSAoaXRzIHRyYW5zY3JpcHRpb25hbCBwcm9maWxlIGlzIG5vdCBwcmVzZW50IGluIHRoZSBleHByZXNzaW9uIG1hdHJpeCkgCiAgc1JOQS5hY3Rpdml0aWVzPC1yZWd1bGF0b3JzLmFjdGl2aXRpZXMubWF0cml4W2dyZXAoIkZuclMiLHJvd25hbWVzKHJlZ3VsYXRvcnMuYWN0aXZpdGllcy5tYXRyaXgpKSxdCiAgc1JOQS5wcmlvcnM8LXJvd25hbWVzKGdzLm1hdHJpeClbd2hpY2goZ3MubWF0cml4WyxncmVwKCJGbnJTIixjb2xuYW1lcyhncy5tYXRyaXgpKV0hPTApXQogIHNSTkEucmVndWxvbi5leHByZXNzaW9uPC1leHByZXNzaW9uLnJlc3BvbnNlLm1hdHJpeFtzUk5BLnByaW9ycyxdCiAgbWVhbi5leHByZXNzaW9uLnNSTkEucmVndWxvbjwtY29sTWVhbnMoc1JOQS5yZWd1bG9uLmV4cHJlc3Npb24pCiAgcGxvdCh4PXNSTkEuYWN0aXZpdGllcyx5PW1lYW4uZXhwcmVzc2lvbi5zUk5BLnJlZ3Vsb24sY29sPXJnYigxLDAsMCwxKSxsd2Q9MSx4bGFiPSJGbnJTIGFjdGl2aXR5Iix5bGFiPSJNZWFuIHRyYW5zY3JpcHRpb24gb2YgdGFyZ2V0cyIsY2V4PTEuNSwgY2V4LmxhYj0xLjUsY2V4LmF4aXM9MS41LCBtYWluPSJGaWcgMUQiKQogICNQZXJmb3JtIGxpbmVhciByZWdyZXNzaW9uCiAgbHIuc1JOQS5hY3Rpdml0eS5yZWd1bG9uPC1sbShtZWFuLmV4cHJlc3Npb24uc1JOQS5yZWd1bG9uIH4gYXMubnVtZXJpYyhzUk5BLmFjdGl2aXRpZXMpKQogIGFibGluZShsci5zUk5BLmFjdGl2aXR5LnJlZ3Vsb24sY29sPSJkYXJrcmVkIixsd2Q9MyxsdHk9MikKICAjQ3JlYXRlIEZpZyAxQwogICNEZWZpbmUgY29ycmVsYXRpb24gYmV0d2VlbiBzUk5BcyBhbmQgdGhlaXIgcHJpb3JzCiAgc1JOQXM8LWNvbG5hbWVzKElOJHByaW9ycy5tYXQpWzE0MDoxNDddCiAgY29ycmVsYXRpb24uc1JOQS5hY3Rpdml0aWVzLnRhcmdldHMuZXhwcmVzc2lvbjwtYygpCiAgY29ycmVsYXRpb24uc1JOQS5leHByZXNzaW9uLnRhcmdldHMuZXhwcmVzc2lvbjwtYygpCiAgZm9yKHQgaW4gc1JOQXNbLThdKQogIHsKICAgIHNSTkEuYWN0aXZpdGllczwtcmVndWxhdG9ycy5hY3Rpdml0aWVzLm1hdHJpeFt0LF0KICAgIHNSTkEuZXhwcmVzc2lvbjwtZXhwcmVzc2lvbi5kZXNpZ24ubWF0cml4W3QsXQogICAgc1JOQS5wcmlvcnM8LW5hbWVzKHdoaWNoKGdzLm1hdHJpeFssdF0hPTApKQogICAgZm9yKGcgaW4gc1JOQS5wcmlvcnMpCiAgICB7CiAgICBjb3JyZWxhdGlvbi5zUk5BLmFjdGl2aXRpZXMudGFyZ2V0cy5leHByZXNzaW9uPC1jKGNvcnJlbGF0aW9uLnNSTkEuYWN0aXZpdGllcy50YXJnZXRzLmV4cHJlc3Npb24sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvcihzUk5BLmFjdGl2aXRpZXMsZXhwcmVzc2lvbi5yZXNwb25zZS5tYXRyaXhbZyxdKSkKICAgIGNvcnJlbGF0aW9uLnNSTkEuZXhwcmVzc2lvbi50YXJnZXRzLmV4cHJlc3Npb248LWMoY29ycmVsYXRpb24uc1JOQS5leHByZXNzaW9uLnRhcmdldHMuZXhwcmVzc2lvbiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29yKHNSTkEuZXhwcmVzc2lvbixleHByZXNzaW9uLnJlc3BvbnNlLm1hdHJpeFtnLF0pKSAgCiAgICB9CiAgfQp0ZW1wb3JhbC5tYXRyaXg8LXJiaW5kKGNiaW5kKGNvcnJlbGF0aW9uLnNSTkEuZXhwcmVzc2lvbi50YXJnZXRzLmV4cHJlc3Npb24scmVwKCJFeHByZXNzaW9uIixsZW5ndGgoY29ycmVsYXRpb24uc1JOQS5leHByZXNzaW9uLnRhcmdldHMuZXhwcmVzc2lvbikpKSxjYmluZChjb3JyZWxhdGlvbi5zUk5BLmFjdGl2aXRpZXMudGFyZ2V0cy5leHByZXNzaW9uLHJlcCgiQWN0aXZpdHkiLGxlbmd0aChjb3JyZWxhdGlvbi5zUk5BLmFjdGl2aXRpZXMudGFyZ2V0cy5leHByZXNzaW9uKSkpKQp0ZW1wb3JhbC5tYXRyaXg8LWFzLmRhdGEuZnJhbWUodGVtcG9yYWwubWF0cml4KQpjb2xuYW1lcyh0ZW1wb3JhbC5tYXRyaXgpPC1jKCJQZWFyc29uQ29ycmVsYXRpb24iLCJUeXBlIikKdGVtcG9yYWwubWF0cml4JFBlYXJzb25Db3JyZWxhdGlvbjwtYXMubnVtZXJpYyhhcy52ZWN0b3IodGVtcG9yYWwubWF0cml4JFBlYXJzb25Db3JyZWxhdGlvbikpCnAgPC0gZ2dwbG90KHRlbXBvcmFsLm1hdHJpeCwgYWVzKHg9VHlwZSwgeT1QZWFyc29uQ29ycmVsYXRpb24sZmlsbD1UeXBlKSkgKyBnZW9tX3Zpb2xpbigpCnAgKyBzdGF0X3N1bW1hcnkoZnVuLnk9bWVkaWFuLCBnZW9tPSJwb2ludCIsIHNpemU9MiwgY29sb3I9InB1cnBsZSIpICsgZ2d0aXRsZSgiRmlnIDFDIikKYGBgCgoxYi4gRXhhbWluZSB0aGUgcmVsYXRpb24gYmV0d2VlbiB0aGUgdHJhbnNjcmlwdGlvbiBvZiBiYWN0ZXJpYWwgc1JOQXMgYW5kIHRoZWlyIHJlZ3VsYXRvcnkgYWN0aXZpdGllcyAtIFBhcnQgSUkgKEZpZyBTMSkKYGBge3J9CiNDcmVhdGUgRmlnIFMxQS1FCm90aGVyLmVjb2xpLnNSTkFzPC1jKCJjeWFSIiwibWljQSIsImdjdkIiLCJvbXJBIiwicnliQiIpCiNMb2FkIHRoZSBvdXRwdXQgb2YgdGhlIEluZmVyZWxhdG9yCmxvYWQoIi4uL0luZmVyZWxhdG9yX291dHB1dF9maWxlcy9FY29saV84c1JOQXMvYmV0YXNfZnJhY190cF8xMDBfcGVybV8xLS1mcmFjX2ZwXzBfcGVybV8xXzEuMS5SRGF0YSIpCmxvYWQoIi4uL0luZmVyZWxhdG9yX291dHB1dF9maWxlcy9FY29saV84c1JOQXMvY29tYmluZWRjb25mX2ZyYWNfdHBfMTAwX3Blcm1fMS0tZnJhY19mcF8wX3Blcm1fMV8xLjEuUkRhdGEiKQpsb2FkKCIuLi9JbmZlcmVsYXRvcl9vdXRwdXRfZmlsZXMvRWNvbGlfOHNSTkFzL3BhcmFtc19hbmRfaW5wdXQuUkRhdGEiKQojRXh0cmFjdCBleHByZXNzaW9uIHJlc3BvbnNlIGFuZCBkZXNpZ24gbWF0cmljZXMKZXhwcmVzc2lvbi5yZXNwb25zZS5tYXRyaXg8LUlOJGZpbmFsX3Jlc3BvbnNlX21hdHJpeApleHByZXNzaW9uLmRlc2lnbi5tYXRyaXg8LUlOJGZpbmFsX2Rlc2lnbl9tYXRyaXgKZ3MubWF0cml4PC1JTiRncy5tYXQKcmVndWxhdG9ycy5hY3Rpdml0aWVzLm1hdHJpeDwtSU4kdGYuYWN0aXZpdGllc1tbMV1dCnBhcihtZnJvdz1jKDEsMikpCmZvcihpIGluIG90aGVyLmVjb2xpLnNSTkFzKQp7CiAgc1JOQS5hY3Rpdml0aWVzPC1yZWd1bGF0b3JzLmFjdGl2aXRpZXMubWF0cml4W2dyZXAoaSxyb3duYW1lcyhyZWd1bGF0b3JzLmFjdGl2aXRpZXMubWF0cml4KSksXQogIHNSTkEudHJhbnNjcmlwdGlvbmFsLnByb2ZpbGU8LWV4cHJlc3Npb24uZGVzaWduLm1hdHJpeFtncmVwKGkscm93bmFtZXMoZXhwcmVzc2lvbi5kZXNpZ24ubWF0cml4KSksXQogIHNSTkEucHJpb3JzPC1yb3duYW1lcyhncy5tYXRyaXgpW3doaWNoKGdzLm1hdHJpeFssZ3JlcChpLGNvbG5hbWVzKGdzLm1hdHJpeCkpXSE9MCldCiAgc1JOQS5yZWd1bG9uLmV4cHJlc3Npb248LWV4cHJlc3Npb24ucmVzcG9uc2UubWF0cml4W3NSTkEucHJpb3JzLF0KICBtZWFuLmV4cHJlc3Npb24uc1JOQS5yZWd1bG9uPC1jb2xNZWFucyhzUk5BLnJlZ3Vsb24uZXhwcmVzc2lvbikKICBwbG90KHg9c1JOQS50cmFuc2NyaXB0aW9uYWwucHJvZmlsZSx5PW1lYW4uZXhwcmVzc2lvbi5zUk5BLnJlZ3Vsb24sY29sPXJnYigxLDAsMCwxKSxsd2Q9MSx4bGFiPXBhc3RlKGksInRyYW5zY3JpcHRpb24iLHNlcD0iICIpLHlsYWI9Ik1lYW4gdHJhbnNjcmlwdGlvbiBvZiB0YXJnZXRzIixjZXg9MS41LCBjZXgubGFiPTEuNSxjZXguYXhpcz0xLjUpCiAgI1BlcmZvcm0gbGluZWFyIHJlZ3Jlc3Npb24KICBsci5zUk5BLmV4cC5yZWd1bG9uPC1sbShtZWFuLmV4cHJlc3Npb24uc1JOQS5yZWd1bG9uIH4gYXMubnVtZXJpYyhzUk5BLnRyYW5zY3JpcHRpb25hbC5wcm9maWxlKSkKICBhYmxpbmUobHIuc1JOQS5leHAucmVndWxvbixjb2w9ImRhcmtyZWQiLGx3ZD0zLGx0eT0yKQogIHBsb3QoeD1zUk5BLmFjdGl2aXRpZXMseT1tZWFuLmV4cHJlc3Npb24uc1JOQS5yZWd1bG9uLGNvbD1yZ2IoMSwwLDAsMSksbHdkPTEseGxhYj1wYXN0ZShjYXBpdGFsaXplKGkpLCJhY3Rpdml0eSIsc2VwPSIgIikseWxhYj0iIixjZXg9MS41LCBjZXgubGFiPTEuNSxjZXguYXhpcz0xLjUpCiAgI1BlcmZvcm0gbGluZWFyIHJlZ3Jlc3Npb24KICBsci5zUk5BLmFjdGl2aXR5LnJlZ3Vsb248LWxtKG1lYW4uZXhwcmVzc2lvbi5zUk5BLnJlZ3Vsb24gfiBhcy5udW1lcmljKHNSTkEuYWN0aXZpdGllcykpCiAgYWJsaW5lKGxyLnNSTkEuYWN0aXZpdHkucmVndWxvbixjb2w9ImRhcmtyZWQiLGx3ZD0zLGx0eT0yKQp9CiNDcmVhdGUgRmlnIFMxRgojTG9hZCBCLiBzdWJ0aWxpcyBydW4KbG9hZCgiLi4vSW5mZXJlbGF0b3Jfb3V0cHV0X2ZpbGVzL0ZzckFfQnN1YnRpbGlzL3BhcmFtc19hbmRfaW5wdXQuUkRhdGEiKQpsb2FkKCIuLi9JbmZlcmVsYXRvcl9vdXRwdXRfZmlsZXMvRnNyQV9Cc3VidGlsaXMvY29tYmluZWRjb25mX2ZyYWNfdHBfMTAwX3Blcm1fMS0tZnJhY19mcF8wX3Blcm1fMV8xLjEuUkRhdGEiKQpsb2FkKCIuLi9JbmZlcmVsYXRvcl9vdXRwdXRfZmlsZXMvRnNyQV9Cc3VidGlsaXMvYmV0YXNfZnJhY190cF8xMDBfcGVybV8xLS1mcmFjX2ZwXzBfcGVybV8xXzEuMS5SRGF0YSIpCiNFeHRyYWN0IGV4cHJlc3Npb24gcmVzcG9uc2UgYW5kIGRlc2lnbiBtYXRyaWNlcwpleHByZXNzaW9uLnJlc3BvbnNlLm1hdHJpeDwtSU4kZmluYWxfcmVzcG9uc2VfbWF0cml4CmV4cHJlc3Npb24uZGVzaWduLm1hdHJpeDwtSU4kZmluYWxfZGVzaWduX21hdHJpeApncy5tYXRyaXg8LUlOJGdzLm1hdApyZWd1bGF0b3JzLmFjdGl2aXRpZXMubWF0cml4PC1JTiR0Zi5hY3Rpdml0aWVzW1sxXV0KRnNyQTwtIm5ld18xNDgzNTM5XzE0ODM2NDAiCnNSTkEuYWN0aXZpdGllczwtcmVndWxhdG9ycy5hY3Rpdml0aWVzLm1hdHJpeFtGc3JBLF0Kc1JOQS50cmFuc2NyaXB0aW9uYWwucHJvZmlsZTwtZXhwcmVzc2lvbi5kZXNpZ24ubWF0cml4W0ZzckEsXQpzUk5BLnByaW9yczwtcm93bmFtZXMoZ3MubWF0cml4KVt3aGljaChncy5tYXRyaXhbLEZzckFdIT0wKV0Kc1JOQS5yZWd1bG9uLmV4cHJlc3Npb248LWV4cHJlc3Npb24ucmVzcG9uc2UubWF0cml4W3NSTkEucHJpb3JzLF0KbWVhbi5leHByZXNzaW9uLnNSTkEucmVndWxvbjwtY29sTWVhbnMoc1JOQS5yZWd1bG9uLmV4cHJlc3Npb24pCnBsb3QoeD1zUk5BLnRyYW5zY3JpcHRpb25hbC5wcm9maWxlLHk9bWVhbi5leHByZXNzaW9uLnNSTkEucmVndWxvbixjb2w9cmdiKDEsMCwwLDEpLGx3ZD0xLHhsYWI9ImZzckEgdHJhbnNjcmlwdGlvbiIseWxhYj0iTWVhbiB0cmFuc2NyaXB0aW9uIG9mIHRhcmdldHMiLGNleD0xLjUsIGNleC5sYWI9MS41LGNleC5heGlzPTEuNSwgbWFpbj0iRmlnIFMxRiIpCiNQZXJmb3JtIGxpbmVhciByZWdyZXNzaW9uCmxyLnNSTkEuZXhwLnJlZ3Vsb248LWxtKG1lYW4uZXhwcmVzc2lvbi5zUk5BLnJlZ3Vsb24gfiBhcy5udW1lcmljKHNSTkEudHJhbnNjcmlwdGlvbmFsLnByb2ZpbGUpKQphYmxpbmUobHIuc1JOQS5leHAucmVndWxvbixjb2w9ImRhcmtyZWQiLGx3ZD0zLGx0eT0yKQpwbG90KHg9c1JOQS5hY3Rpdml0aWVzLHk9bWVhbi5leHByZXNzaW9uLnNSTkEucmVndWxvbixjb2w9cmdiKDEsMCwwLDEpLGx3ZD0xLHhsYWI9IkZzckEgYWN0aXZpdHkiLHlsYWI9IiIsY2V4PTEuNSwgY2V4LmxhYj0xLjUsY2V4LmF4aXM9MS41KQojUGVyZm9ybSBsaW5lYXIgcmVncmVzc2lvbgpsci5zUk5BLmFjdGl2aXR5LnJlZ3Vsb248LWxtKG1lYW4uZXhwcmVzc2lvbi5zUk5BLnJlZ3Vsb24gfiBhcy5udW1lcmljKHNSTkEuYWN0aXZpdGllcykpCmFibGluZShsci5zUk5BLmFjdGl2aXR5LnJlZ3Vsb24sY29sPSJkYXJrcmVkIixsd2Q9MyxsdHk9MikKI0NyZWF0ZSBGaWcgUzFGCiNMb2FkIFMuIGF1cmV1cyBydW4KbG9hZCgiLi4vSW5mZXJlbGF0b3Jfb3V0cHV0X2ZpbGVzL1JzYUVfU2F1cmV1cy9wYXJhbXNfYW5kX2lucHV0LlJEYXRhIikKbG9hZCgiLi4vSW5mZXJlbGF0b3Jfb3V0cHV0X2ZpbGVzL1JzYUVfU2F1cmV1cy9jb21iaW5lZGNvbmZfZnJhY190cF8xMDBfcGVybV8xLS1mcmFjX2ZwXzBfcGVybV8xXzEuMS5SRGF0YSIpCmxvYWQoIi4uL0luZmVyZWxhdG9yX291dHB1dF9maWxlcy9Sc2FFX1NhdXJldXMvYmV0YXNfZnJhY190cF8xMDBfcGVybV8xLS1mcmFjX2ZwXzBfcGVybV8xXzEuMS5SRGF0YSIpCiNFeHRyYWN0IGV4cHJlc3Npb24gcmVzcG9uc2UgYW5kIGRlc2lnbiBtYXRyaWNlcwpleHByZXNzaW9uLnJlc3BvbnNlLm1hdHJpeDwtSU4kZmluYWxfcmVzcG9uc2VfbWF0cml4CmV4cHJlc3Npb24uZGVzaWduLm1hdHJpeDwtSU4kZmluYWxfZGVzaWduX21hdHJpeApncy5tYXRyaXg8LUlOJGdzLm1hdApyZWd1bGF0b3JzLmFjdGl2aXRpZXMubWF0cml4PC1JTiR0Zi5hY3Rpdml0aWVzW1sxXV0KUnNhRTwtIm5ld185MTEzNjhfOTExNDY1XzEiCnNSTkEuYWN0aXZpdGllczwtcmVndWxhdG9ycy5hY3Rpdml0aWVzLm1hdHJpeFtSc2FFLF0Kc1JOQS50cmFuc2NyaXB0aW9uYWwucHJvZmlsZTwtZXhwcmVzc2lvbi5kZXNpZ24ubWF0cml4W1JzYUUsXQpzUk5BLnByaW9yczwtcm93bmFtZXMoZ3MubWF0cml4KVt3aGljaChncy5tYXRyaXhbLFJzYUVdIT0wKV0Kc1JOQS5yZWd1bG9uLmV4cHJlc3Npb248LWV4cHJlc3Npb24ucmVzcG9uc2UubWF0cml4W3NSTkEucHJpb3JzLF0KbWVhbi5leHByZXNzaW9uLnNSTkEucmVndWxvbjwtY29sTWVhbnMoc1JOQS5yZWd1bG9uLmV4cHJlc3Npb24pCnBsb3QoeD1zUk5BLnRyYW5zY3JpcHRpb25hbC5wcm9maWxlLHk9bWVhbi5leHByZXNzaW9uLnNSTkEucmVndWxvbixjb2w9cmdiKDEsMCwwLDEpLGx3ZD0xLHhsYWI9InJzYUUgdHJhbnNjcmlwdGlvbiIseWxhYj0iTWVhbiB0cmFuc2NyaXB0aW9uIG9mIHRhcmdldHMiLGNleD0xLjUsIGNleC5sYWI9MS41LGNleC5heGlzPTEuNSwgbWFpbj0iRmlnIFMxRyIpCiNQZXJmb3JtIGxpbmVhciByZWdyZXNzaW9uCmxyLnNSTkEuZXhwLnJlZ3Vsb248LWxtKG1lYW4uZXhwcmVzc2lvbi5zUk5BLnJlZ3Vsb24gfiBhcy5udW1lcmljKHNSTkEudHJhbnNjcmlwdGlvbmFsLnByb2ZpbGUpKQphYmxpbmUobHIuc1JOQS5leHAucmVndWxvbixjb2w9ImRhcmtyZWQiLGx3ZD0zLGx0eT0yKQpwbG90KHg9c1JOQS5hY3Rpdml0aWVzLHk9bWVhbi5leHByZXNzaW9uLnNSTkEucmVndWxvbixjb2w9cmdiKDEsMCwwLDEpLGx3ZD0xLHhsYWI9IlJzYUUgYWN0aXZpdHkiLHlsYWI9IiIsY2V4PTEuNSwgY2V4LmxhYj0xLjUsY2V4LmF4aXM9MS41KQojUGVyZm9ybSBsaW5lYXIgcmVncmVzc2lvbgpsci5zUk5BLmFjdGl2aXR5LnJlZ3Vsb248LWxtKG1lYW4uZXhwcmVzc2lvbi5zUk5BLnJlZ3Vsb24gfiBhcy5udW1lcmljKHNSTkEuYWN0aXZpdGllcykpCmFibGluZShsci5zUk5BLmFjdGl2aXR5LnJlZ3Vsb24sY29sPSJkYXJrcmVkIixsd2Q9MyxsdHk9MikKYGBgCjJhLiBFdmFsdWF0ZSBwZXJmb3JtYW5jZSBvZiB0aGUgSW5mZXJlbGF0b3IgYW5kIENMUiB3aXRoIGFuZCB3aXRob3V0IHNSTkEgYWN0aXZpdGllcyAoRmlnIDNBKQpgYGB7cn0KI1Bsb3QgcGVyZm9ybWFuY2Ugb2YgdGhlIEluZmVyZWxhdG9yIHdpdGggc1JOQSBhY3Rpdml0aWVzCiNMb2FkIHRoZSBvdXRwdXQgZmlsZXMgb2YgdGhlIEluZmVyZWxhdG9yIHJ1biBmb3IgRS4gY29saQpsb2FkKCIuLi9JbmZlcmVsYXRvcl9vdXRwdXRfZmlsZXMvRWNvbGlfOHNSTkFzL2JldGFzX2ZyYWNfdHBfMTAwX3Blcm1fMS0tZnJhY19mcF8wX3Blcm1fMV8xLjEuUkRhdGEiKQpsb2FkKCIuLi9JbmZlcmVsYXRvcl9vdXRwdXRfZmlsZXMvRWNvbGlfOHNSTkFzL2NvbWJpbmVkY29uZl9mcmFjX3RwXzEwMF9wZXJtXzEtLWZyYWNfZnBfMF9wZXJtXzFfMS4xLlJEYXRhIikKbG9hZCgiLi4vSW5mZXJlbGF0b3Jfb3V0cHV0X2ZpbGVzL0Vjb2xpXzhzUk5Bcy9wYXJhbXNfYW5kX2lucHV0LlJEYXRhIikKI05vcm1hbGl6ZSBjb25maWRlbmNlIHNjb3JlIG1hdHJpeApzb3VyY2UoIi4uL01pc2NlbGxhbmVvdXNfc2NyaXB0cy9jcmVhdGVfZmluYWxfbmV0d29ya3MuUiIpCiNTYXZlIHRoZSBuYW1lcyBvZiBzUk5BcyB0byBiZSBjb25zaWRlcmVkIGluIHRoaXMgYW5hbHlzaXMgKEZuclMgaXMgbm90IGluY2x1ZGVkKQpzUk5BczwtY29sbmFtZXMoSU4kcHJpb3JzLm1hdClbMTQwOjE0Nl0KI0NyZWF0ZSBtYXRyaXggd2l0aCBub3JtYWxpemVkIGNvbmZpZGVuY2Ugc2NvcmUgZm9yIHNlbGVjdGVkIHNSTkFzCm5vcm1hbGl6ZWQuY29uZmlkZW5jZS5tYXRyaXguc1JOQXM8LW5vcm1hbGl6ZWQuY29uZmlkZW5jZS5tYXRyaXhbLHNSTkFzXQojQ29udmVydCBzUk5BIHByaW9ycyB0byB6ZXJvZXMgaW4gdGhlIG5vcm1hbGl6ZWQgY29uZmlkZW5jZSBzY29yZSBtYXRyaXgKbm9ybWFsaXplZC5jb25maWRlbmNlLm1hdHJpeC5zUk5Bc1t3aGljaChJTiRwcmlvcnMubWF0WyxzUk5Bc10hPTApXTwtMAojUnVuIHNjcmlwdCB0byByZWFkIGFsbCBjYW5kaWRhdGUgc1JOQSB0YXJnZXRzIHN1cHBvcnRlZCBieSBleHBlcmltZW50YWwgZGF0YSBhbmQgZ2Vub21pYyBsb2NhdGlvbiAob3Blcm9ucykKc291cmNlKCIuLi9NaXNjZWxsYW5lb3VzX3NjcmlwdHMvc1JOQV9jYW5kaWRhdGVfdGFyZ2V0c19jb21waWxhdGlvbi5SIikKI0NyZWF0ZSB2ZWN0b3IgdG8gc2F2ZSBudW1iZXIgb2Ygc3VwcG9ydGVkIHByaW9ycyBhdCBkaWZmZXJlbnQgcmFua2luZyBwb3NpdGlvbnMgcGVyIHNSTkEgCnBlcmZvcm1hbmNlLmluZmVyZWxhdG9yLnNSTkEuYWN0aXZpdHk8LWMoKQpmb3IoeSBpbiAxOjEwMCkKewp0b3RhbC5zdXBwb3J0ZWQucHJlZGljdGlvbnM8LTAKZm9yKHMgaW4gY29sbmFtZXMobm9ybWFsaXplZC5jb25maWRlbmNlLm1hdHJpeC5zUk5BcykpCnsKICBjYW5kaWRhdGUudGFyZ2V0czwtdW5pcXVlKGV4cGFuZGVkLnNSTkEuZ3Nbd2hpY2goZXhwYW5kZWQuc1JOQS5nc1ssMV09PSBzKSwyXSkKICB0b3AudGFyZ2V0czwtcm93bmFtZXMobm9ybWFsaXplZC5jb25maWRlbmNlLm1hdHJpeC5zUk5Bcylbb3JkZXIobm9ybWFsaXplZC5jb25maWRlbmNlLm1hdHJpeC5zUk5Bc1ssc10sZGVjcmVhc2luZz1UKVsxOnldXQogICNLZWVwIG9ubHkgdGhlIGxvY2kgdGFncwogIHRvcC50YXJnZXRzPC10cmFuc2xhdGUubmFtZXModG9wLnRhcmdldHMpCiAgdG90YWwuc3VwcG9ydGVkLnByZWRpY3Rpb25zIDwtIHRvdGFsLnN1cHBvcnRlZC5wcmVkaWN0aW9ucyArIGxlbmd0aChpbnRlcnNlY3QoY2FuZGlkYXRlLnRhcmdldHMsdG9wLnRhcmdldHMpKQp9CnBlcmZvcm1hbmNlLmluZmVyZWxhdG9yLnNSTkEuYWN0aXZpdHk8LWMocGVyZm9ybWFuY2UuaW5mZXJlbGF0b3Iuc1JOQS5hY3Rpdml0eSx0b3RhbC5zdXBwb3J0ZWQucHJlZGljdGlvbnMpCn0KcGxvdCh4PTE6MTAwLCB5PXBlcmZvcm1hbmNlLmluZmVyZWxhdG9yLnNSTkEuYWN0aXZpdHkseWxpbT1jKDAsNzIpLHhsYWI9IlRhcmdldHMgcGVyIHNSTkEiLHlsYWI9IlN1cHBvcnRlZCBwcmVkaWN0aW9ucyIsY29sPSJkYXJrIGdyZWVuIix0eXBlPSJsaW5lcyIsbHdkPTIsY2V4PTEuNSxjZXgubGFiPTEuNSxjZXguYXhpcz0xLjUpCiNQbG90IHBlcmZvcm1hbmNlIG9mIENMUiB3aXRob3V0IHNSTkEgYWN0aXZpdGllcyAoc1JOQSBleHByZXNzaW9uIGluc3RlYWQpIHVzaW5nIHNjcmlwdCBpbiB0aGUgZm9sZGVyIG9mIHRoZSBJbmZlcmVsYXRvciBjb2RlIApzb3VyY2UoIi4uL0luZmVyZWxhdG9yXzIwMTUuMDguMDUvUl9zY3JpcHRzL21pX2FuZF9jbHIuUiIpCiNSZW1vdmUgRm5yUyBmcm9tIHRoZSBzZXQgb2YgcG90ZW50aWFsIHJlZ3VsYXRvcnMKcmVndWxhdG9ycy5uYW1lczwtSU4kdGYubmFtZXNbLTE0N10KWDwtSU4kZmluYWxfZGVzaWduX21hdHJpeFtyZWd1bGF0b3JzLm5hbWVzLF0KI1RoaXMgaXMgdGhlIHNhbWUgSU4kZmluYWxfcmVzcG9uc2VfbWF0cml4IGJlY2F1c2Ugd2UgZGlkIG5vdCB1c2UgYSBtZXRhZGF0YSBmaWxlIChmb3IgdGltZSBzZXJpZXMpIApZPC1JTiRmaW5hbF9yZXNwb25zZV9tYXRyaXhfaGFsZnRhdSAKI0NhbGN1bGF0ZSBtdXR1YWwgaW5mb3JtYXRpb24gKE1JKSBhcyBkb25lIGluIHRoZSBJbmZlcmVsYXRvcgpNcyA8LSBtaSh0KFkpLCB0KFgpLCBuYmlucz1QQVJTJG1pLmJpbnMsIGNwdS5uPVBBUlMkY29yZXMpICAKZGlhZyhNcykgPC0gMApNc19iZyA8LSBtaSh0KFgpLCB0KFgpLCBuYmlucz1QQVJTJG1pLmJpbnMsIGNwdS5uPVBBUlMkY29yZXMpCmRpYWcoTXNfYmcpIDwtIDAKI0NhbGN1bGF0ZSBDTFIKY2xyLm1hdHJpeCA9IG1peGVkQ0xSKE1zX2JnLE1zKQpkaW1uYW1lcyhjbHIubWF0cml4KSA8LSBsaXN0KHJvd25hbWVzKFkpLCByb3duYW1lcyhYKSkKI05hbWVzIG9mIHNSTkEgdG8gYmUgY29uc2lkZXJlZCBpbiB0aGlzIGFuYWx5c2lzIChGbnJTIGlzIG5vdCBpbmNsdWRlZCkKc1JOQXM8LWNvbG5hbWVzKElOJHByaW9ycy5tYXQpWzE0MDoxNDZdCiNDcmVhdGUgbWF0cml4IHdpdGggbm9ybWFsaXplZCBDTFIgc2NvcmVzIGZvciBzZWxlY3RlZCBzUk5BcwpjbHIubWF0cml4LnNSTkFzPC1jbHIubWF0cml4WyxzUk5Bc10KcGVyZm9ybWFuY2UuY2xyLnNSTkEuZXhwPC1jKCkKZm9yKHkgaW4gMToxMDApCnsKdG90YWwuc3VwcG9ydGVkLnByZWRpY3Rpb25zPC0wCmZvcihzIGluIGNvbG5hbWVzKGNsci5tYXRyaXguc1JOQXMpKQp7CiAgY2FuZGlkYXRlLnRhcmdldHM8LXVuaXF1ZShleHBhbmRlZC5zUk5BLmdzW3doaWNoKGV4cGFuZGVkLnNSTkEuZ3NbLDFdPT0gcyksMl0pCiAgdG9wLnRhcmdldHM8LXJvd25hbWVzKGNsci5tYXRyaXguc1JOQXMpW29yZGVyKGNsci5tYXRyaXguc1JOQXNbLHNdLGRlY3JlYXNpbmc9VClbMTp5XV0KICB0b3AudGFyZ2V0czwtdHJhbnNsYXRlLm5hbWVzKHRvcC50YXJnZXRzKQogIHRvdGFsLnN1cHBvcnRlZC5wcmVkaWN0aW9ucyA8LSB0b3RhbC5zdXBwb3J0ZWQucHJlZGljdGlvbnMgKyBsZW5ndGgoaW50ZXJzZWN0KGNhbmRpZGF0ZS50YXJnZXRzLHRvcC50YXJnZXRzKSkKfQpwZXJmb3JtYW5jZS5jbHIuc1JOQS5leHA8LWMocGVyZm9ybWFuY2UuY2xyLnNSTkEuZXhwLHRvdGFsLnN1cHBvcnRlZC5wcmVkaWN0aW9ucykKfQpsaW5lcyh4PTE6MTAwLCB5PXBlcmZvcm1hbmNlLmNsci5zUk5BLmV4cCxjb2w9Im9yYW5nZSIsbHdkPTIpCiNQbG90IHBlcmZvcm1hbmNlIG9mIENMUiB3aXRoIHNSTkEgYWN0aXZpdGllcwpYPC1JTiR0Zi5hY3Rpdml0aWVzW1sxXV0KWTwtSU4kZmluYWxfcmVzcG9uc2VfbWF0cml4X2hhbGZ0YXUKI0NhbGN1bGF0ZSBtdXR1YWwgaW5mb3JtYXRpb24gKE1JKSBhcyBkb25lIGluIHRoZSBJbmZlcmVsYXRvcgpNcyA8LSBtaSh0KFkpLCB0KFgpLCBuYmlucz1QQVJTJG1pLmJpbnMsIGNwdS5uPVBBUlMkY29yZXMpICAKZGlhZyhNcykgPC0gMApNc19iZyA8LSBtaSh0KFgpLCB0KFgpLCBuYmlucz1QQVJTJG1pLmJpbnMsIGNwdS5uPVBBUlMkY29yZXMpCmRpYWcoTXNfYmcpIDwtIDAKI0NhbGN1bGF0ZSBDTFIKY2xyLm1hdHJpeCA9IG1peGVkQ0xSKE1zX2JnLE1zKQpkaW1uYW1lcyhjbHIubWF0cml4KSA8LSBsaXN0KHJvd25hbWVzKFkpLCByb3duYW1lcyhYKSkKI0NyZWF0ZSBtYXRyaXggd2l0aCBub3JtYWxpemVkIGNsciBzY29yZXMgZm9yIHNlbGVjdGVkIHNSTkFzCmNsci5tYXRyaXguc1JOQXM8LWNsci5tYXRyaXhbLHNSTkFzXQojQ29udmVydCBzUk5BIHByaW9ycyB0byB6ZXJvZXMgaW4gdGhlIENMUiBtYXRyaXgKY2xyLm1hdHJpeC5zUk5Bc1t3aGljaChJTiRwcmlvcnMubWF0WyxzUk5Bc10hPTApXTwtMApwZXJmb3JtYW5jZS5jbHIuc1JOQS5hY3Q8LWMoKQpmb3IoeSBpbiAxOjEwMCkKewp0b3RhbC5zdXBwb3J0ZWQucHJlZGljdGlvbnM8LTAKZm9yKHMgaW4gY29sbmFtZXMoY2xyLm1hdHJpeC5zUk5BcykpCnsKICBjYW5kaWRhdGUudGFyZ2V0czwtdW5pcXVlKGV4cGFuZGVkLnNSTkEuZ3Nbd2hpY2goZXhwYW5kZWQuc1JOQS5nc1ssMV09PSBzKSwyXSkKICB0b3AudGFyZ2V0czwtcm93bmFtZXMoY2xyLm1hdHJpeC5zUk5Bcylbb3JkZXIoY2xyLm1hdHJpeC5zUk5Bc1ssc10sZGVjcmVhc2luZz1UKVsxOnldXQogIHRvcC50YXJnZXRzPC10cmFuc2xhdGUubmFtZXModG9wLnRhcmdldHMpCiAgdG90YWwuc3VwcG9ydGVkLnByZWRpY3Rpb25zIDwtIHRvdGFsLnN1cHBvcnRlZC5wcmVkaWN0aW9ucyArIGxlbmd0aChpbnRlcnNlY3QoY2FuZGlkYXRlLnRhcmdldHMsdG9wLnRhcmdldHMpKQp9CnBlcmZvcm1hbmNlLmNsci5zUk5BLmFjdDwtYyhwZXJmb3JtYW5jZS5jbHIuc1JOQS5hY3QsdG90YWwuc3VwcG9ydGVkLnByZWRpY3Rpb25zKQp9CmxpbmVzKHg9MToxMDAsIHk9cGVyZm9ybWFuY2UuY2xyLnNSTkEuYWN0LGNvbD0iYmx1ZSIsbHdkPTIpCiNQbG90IHBlcmZvcm1hbmNlIG9mIHRoZSBJbmZlcmVsYXRvciB3aXRob3V0IHNSTkEgYWN0aXZpdGllcyAobm8gVEYgb3Igc1JOQSBwcmlvcnMgd2VyZSBzcGVjaWZpZWQpCiNMb2FkIEluZmVyZWxhdG9yIG91dHB1dApsb2FkKCIuLi9JbmZlcmVsYXRvcl9vdXRwdXRfZmlsZXMvRWNvbGlfd2l0aG91dF9yZWd1bGF0b3JzX3ByaW9ycy9iZXRhc19mcmFjX3RwXzEwMF9wZXJtXzEtLWZyYWNfZnBfMF9wZXJtXzFfMC5SRGF0YSIpCmxvYWQoIi4uL0luZmVyZWxhdG9yX291dHB1dF9maWxlcy9FY29saV93aXRob3V0X3JlZ3VsYXRvcnNfcHJpb3JzL2NvbWJpbmVkY29uZl9mcmFjX3RwXzEwMF9wZXJtXzEtLWZyYWNfZnBfMF9wZXJtXzFfMC5SRGF0YSIpCmxvYWQoIi4uL0luZmVyZWxhdG9yX291dHB1dF9maWxlcy9FY29saV93aXRob3V0X3JlZ3VsYXRvcnNfcHJpb3JzL3BhcmFtc19hbmRfaW5wdXQuUkRhdGEiKQojQ3JlYXRlIG1hdHJpeCB3aXRoIG5vcm1hbGl6ZWQgY29uZmlkZW5jZSBzY29yZSBmb3Igc2VsZWN0ZWQgc1JOQXMKbm9ybWFsaXplZC5jb25maWRlbmNlLm1hdHJpeDwtbm9ybWFsaXphdGlvbihhcy5tYXRyaXgoY29tYi5jb25mcykpCm5vcm1hbGl6ZWQuY29uZmlkZW5jZS5tYXRyaXguc1JOQXM8LW5vcm1hbGl6ZWQuY29uZmlkZW5jZS5tYXRyaXhbLHNSTkFzXQpwZXJmb3JtYW5jZS5pbmZlcmVsYXRvci5zUk5BLmV4cDwtYygpCmZvcih5IGluIDE6MTAwKQp7CnRvdGFsLnN1cHBvcnRlZC5wcmVkaWN0aW9uczwtMApmb3IocyBpbiBjb2xuYW1lcyhub3JtYWxpemVkLmNvbmZpZGVuY2UubWF0cml4LnNSTkFzKSkKewogIGNhbmRpZGF0ZS50YXJnZXRzPC11bmlxdWUoZXhwYW5kZWQuc1JOQS5nc1t3aGljaChleHBhbmRlZC5zUk5BLmdzWywxXT09IHMpLDJdKQogIHRvcC50YXJnZXRzPC1yb3duYW1lcyhub3JtYWxpemVkLmNvbmZpZGVuY2UubWF0cml4LnNSTkFzKVtvcmRlcihub3JtYWxpemVkLmNvbmZpZGVuY2UubWF0cml4LnNSTkFzWyxzXSxkZWNyZWFzaW5nPVQpWzE6eV1dCiAgdG9wLnRhcmdldHM8LXRyYW5zbGF0ZS5uYW1lcyh0b3AudGFyZ2V0cykKICB0b3RhbC5zdXBwb3J0ZWQucHJlZGljdGlvbnMgPC0gdG90YWwuc3VwcG9ydGVkLnByZWRpY3Rpb25zICsgbGVuZ3RoKGludGVyc2VjdChjYW5kaWRhdGUudGFyZ2V0cyx0b3AudGFyZ2V0cykpCn0KcGVyZm9ybWFuY2UuaW5mZXJlbGF0b3Iuc1JOQS5leHA8LWMocGVyZm9ybWFuY2UuaW5mZXJlbGF0b3Iuc1JOQS5leHAsdG90YWwuc3VwcG9ydGVkLnByZWRpY3Rpb25zKQp9CmxpbmVzKHg9MToxMDAsIHk9cGVyZm9ybWFuY2UuaW5mZXJlbGF0b3Iuc1JOQS5leHAsY29sPSJwdXJwbGUiLGx3ZD0yKQojUGxvdCBwZXJmb3JtYW5jZSBvZiB0aGUgSW5mZXJlbGF0b3Igd2l0aCBzUk5BIGFjdGl2aXRpZXMgYW5kIHNodWZmbGVkIHNSTkEgcHJpb3JzCnBlcmZvcm1hbmNlLmluZmVyZWxhdG9yLnNodWZmbGVkLnNSTkEucHJpb3JzPC1jKCkKZm9yKHIgaW4gMToxMCkKewogIHNodWZmbGVkLnBhdGg8LXBhc3RlKCIuLi9JbmZlcmVsYXRvcl9vdXRwdXRfZmlsZXMvRWNvbGlfc2h1ZmZsZWRfc1JOQV9wcmlvcnMvRWNvbGlfc2h1ZmZsZWRfc1JOQV9wcmlvcnMiLHIsIi8iLHNlcD0iIikKICAjTG9hZCBJbmZlcmVsYXRvciBvdXRwdXQgZmlsZXMKICBsb2FkKHBhc3RlKHNodWZmbGVkLnBhdGgsImNvbWJpbmVkY29uZl9mcmFjX3RwXzEwMF9wZXJtXzEtLWZyYWNfZnBfMF9wZXJtXzFfMS4xLlJEYXRhIixzZXA9IiIpKQogIGxvYWQocGFzdGUoc2h1ZmZsZWQucGF0aCwicGFyYW1zX2FuZF9pbnB1dC5SRGF0YSIsc2VwPSIiKSkKICBsb2FkKHBhc3RlKHNodWZmbGVkLnBhdGgsImJldGFzX2ZyYWNfdHBfMTAwX3Blcm1fMS0tZnJhY19mcF8wX3Blcm1fMV8xLjEuUkRhdGEiLHNlcD0iIikpCiAgI0NyZWF0ZSBtYXRyaXggd2l0aCBub3JtYWxpemVkIGNvbmZpZGVuY2Ugc2NvcmUgZm9yIHNlbGVjdGVkIHNSTkFzCiAgbm9ybWFsaXplZC5jb25maWRlbmNlLm1hdHJpeC5zaHVmZmxlZC5wcmlvcnM8LW5vcm1hbGl6YXRpb24oYXMubWF0cml4KGNvbWIuY29uZnMpKQogIG5vcm1hbGl6ZWQuY29uZmlkZW5jZS5tYXRyaXguc2h1ZmZsZWQucHJpb3JzLnNSTkFzPC1ub3JtYWxpemVkLmNvbmZpZGVuY2UubWF0cml4LnNodWZmbGVkLnByaW9yc1ssc1JOQXNdCiAgI0NvbnZlcnQgc1JOQSBwcmlvcnMgdG8gemVyb2VzIGluIHRoZSBub3JtYWxpemVkIGNvbmZpZGVuY2Ugc2NvcmUgbWF0cml4CiAgbm9ybWFsaXplZC5jb25maWRlbmNlLm1hdHJpeC5zaHVmZmxlZC5wcmlvcnMuc1JOQXNbd2hpY2goSU4kcHJpb3JzLm1hdFssc1JOQXNdIT0wKV08LTAKICB0ZW1wb3JhbC5wZXJmb3JtYW5jZTwtYygpCiAgZm9yKHkgaW4gMToxMDApCiAgewogIHRvdGFsLnN1cHBvcnRlZC5wcmVkaWN0aW9uczwtMAogIGZvcihzIGluIGNvbG5hbWVzKGNsci5tYXRyaXguc1JOQXMpKQogIHsKICBjYW5kaWRhdGUudGFyZ2V0czwtdW5pcXVlKGV4cGFuZGVkLnNSTkEuZ3Nbd2hpY2goZXhwYW5kZWQuc1JOQS5nc1ssMV09PSBzKSwyXSkKICB0b3AudGFyZ2V0czwtcm93bmFtZXMobm9ybWFsaXplZC5jb25maWRlbmNlLm1hdHJpeC5zaHVmZmxlZC5wcmlvcnMuc1JOQXMpW29yZGVyKG5vcm1hbGl6ZWQuY29uZmlkZW5jZS5tYXRyaXguc2h1ZmZsZWQucHJpb3JzLnNSTkFzWyxzXSxkZWNyZWFzaW5nPVQpWzE6eV1dCiAgdG9wLnRhcmdldHM8LXRyYW5zbGF0ZS5uYW1lcyh0b3AudGFyZ2V0cykKICB0b3RhbC5zdXBwb3J0ZWQucHJlZGljdGlvbnMgPC0gdG90YWwuc3VwcG9ydGVkLnByZWRpY3Rpb25zICsgbGVuZ3RoKGludGVyc2VjdChjYW5kaWRhdGUudGFyZ2V0cyx0b3AudGFyZ2V0cykpCiAgfQogIHRlbXBvcmFsLnBlcmZvcm1hbmNlPC1jKHRlbXBvcmFsLnBlcmZvcm1hbmNlLHRvdGFsLnN1cHBvcnRlZC5wcmVkaWN0aW9ucykKICB9CiAgcGVyZm9ybWFuY2UuaW5mZXJlbGF0b3Iuc2h1ZmZsZWQuc1JOQS5wcmlvcnM8LXJiaW5kKHBlcmZvcm1hbmNlLmluZmVyZWxhdG9yLnNodWZmbGVkLnNSTkEucHJpb3JzLHRlbXBvcmFsLnBlcmZvcm1hbmNlKQogIH0KICBsaW5lcyh4PTE6MTAwLCB5PWNvbE1lYW5zKHBlcmZvcm1hbmNlLmluZmVyZWxhdG9yLnNodWZmbGVkLnNSTkEucHJpb3JzKSxjb2w9ImRhcmsgZ3JleSIsbHdkPTIpCiAgbGVnZW5kKCJ0b3BsZWZ0IixpbnNldD0wLjAzLGJveC5sdHk9MC4xLGJveC5sd2Q9MC4yLGMoIkJCU1IuU1JBIiwiQkJTUi5TUkEuU2h1ZmZsZWQiLCJCQlNSIiwiQ0xSLlNSQSIsIkNMUiIpLGNvbD1jKCJkYXJrIGdyZWVuIiwiZGFyayBncmV5IiwicHVycGxlIiwiYmx1ZSIsIm9yYW5nZSIpLGNleD0wLjY1LGx0eT0xLGx3ZD0yKQpgYGAKMmIuIFZpc3VhbGx5IGluc3BlY3QgdGhlIGluZmVyZWQgRS5jb2xpIHNSTkEgbmV0d29yay4gRmlnIDNCIHdhcyBjcmVhdGVkIGluIEN5dG9zY2FwZS4gSGVyZSB3ZSB1c2UgdGhlIGlncmFwaCBwYWNrYWdlIHRvIGdldCBhIHJhdyBkcmFmdC4KYGBge3J9CiNMb2FkIHRoZSBvdXRwdXQgZmlsZXMgb2YgdGhlIEluZmVyZWxhdG9yIHJ1biBmb3IgRS4gY29saQpsb2FkKCIuLi9JbmZlcmVsYXRvcl9vdXRwdXRfZmlsZXMvRWNvbGlfOHNSTkFzL2JldGFzX2ZyYWNfdHBfMTAwX3Blcm1fMS0tZnJhY19mcF8wX3Blcm1fMV8xLjEuUkRhdGEiKQpsb2FkKCIuLi9JbmZlcmVsYXRvcl9vdXRwdXRfZmlsZXMvRWNvbGlfOHNSTkFzL2NvbWJpbmVkY29uZl9mcmFjX3RwXzEwMF9wZXJtXzEtLWZyYWNfZnBfMF9wZXJtXzFfMS4xLlJEYXRhIikKbG9hZCgiLi4vSW5mZXJlbGF0b3Jfb3V0cHV0X2ZpbGVzL0Vjb2xpXzhzUk5Bcy9wYXJhbXNfYW5kX2lucHV0LlJEYXRhIikKI0NyZWF0ZSBmaW5hbCBuZXR3b3JrIG1vZGVsCnNvdXJjZSgiLi4vTWlzY2VsbGFuZW91c19zY3JpcHRzL2NyZWF0ZV9maW5hbF9uZXR3b3Jrcy5SIikKI0NyZWF0ZSB0YWJsZSB3aXRoIHNSTkEtbVJOQSBpbnRlcmFjdGlvbnMgZm9yIGFsbCBlaWdodCBzUk5BcwpzUk5BczwtY29sbmFtZXMoSU4kcHJpb3JzLm1hdClbMTQwOjE0N10KI0Z1bmN0aW9uIHRvIHJlbW92ZSB0aGUgbG9jaSBwYXJ0IG9mIGdlbmUgSURzIHVzZWQgaW4gZXhwcmVzc2lvbiwgY29uZmlkZW5jZSBzY29yZSBhbmQgYmV0YXMgbWF0cmljZXMKcmVtb3ZlLmxvY3VzLnRhZzwtZnVuY3Rpb24oZ2VuZU5hbWVzKQp7CiAgb3V0cHV0PC1zYXBwbHkoMTpsZW5ndGgoZ2VuZU5hbWVzKSxmdW5jdGlvbih4KXtzdHJzcGxpdChhcy5jaGFyYWN0ZXIoZ2VuZU5hbWVzKVt4XSxzcGxpdCA9ICJfIilbWzFdXVsxXX0pCiAgb3V0cHV0Cn0KI0Z1bmN0aW9uIHRvIGNyZWF0ZSB0aGUgc1JOQSBuZXR3b3JrIC0gaXQgdXNlcyBmaW5hbCBuZXR3b3JrIG1vZGVsIGNyZWF0ZWQgYWJvdmUKY3JlYXRlLm5ldHdvcms8LWZ1bmN0aW9uKHJlZ3VsYXRvcnNOYW1lcyxyZWNvdmVyZWRJbnRlcmFjdGlvbnNNYXRyaXgsbm92ZWxJbnRlcmFjdGlvbnNNYXRyaXgsYmV0YXMpCnsKb3V0cHV0Lm5ldHdvcms8LWMoKQpmb3IoZyBpbiByZWd1bGF0b3JzTmFtZXMpCnsKICByZWNvdmVyZWQudGFyZ2V0czwtbmFtZXMod2hpY2gocmVjb3ZlcmVkSW50ZXJhY3Rpb25zTWF0cml4WyxnXSE9MCkpCiAgbm92ZWwudGFyZ2V0czwtbmFtZXMod2hpY2gobm92ZWxJbnRlcmFjdGlvbnNNYXRyaXhbLGddIT0wKSkKICBnPC1yZW1vdmUubG9jdXMudGFnKGcpCiAgaWYobGVuZ3RoKHJlY292ZXJlZC50YXJnZXRzKT4wKQogIHsKICAKICBvdXRwdXQubmV0d29yazwtcmJpbmQob3V0cHV0Lm5ldHdvcmssY2JpbmQocmVwKGcsbGVuZ3RoKHJlY292ZXJlZC50YXJnZXRzKSkscmVtb3ZlLmxvY3VzLnRhZyhyZWNvdmVyZWQudGFyZ2V0cykKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAscmVwKCJwcmlvciIsbGVuZ3RoKHJlY292ZXJlZC50YXJnZXRzKSkpKQogIH0KICBpZihsZW5ndGgobm92ZWwudGFyZ2V0cyk+MCkKICB7CiAgb3V0cHV0Lm5ldHdvcms8LXJiaW5kKG91dHB1dC5uZXR3b3JrLGNiaW5kKHJlcChnLGxlbmd0aChub3ZlbC50YXJnZXRzKSkscmVtb3ZlLmxvY3VzLnRhZyhub3ZlbC50YXJnZXRzKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICxyZXAoIm5vdmVsIixsZW5ndGgobm92ZWwudGFyZ2V0cykpKSkKICB9Cn0KY29sbmFtZXMob3V0cHV0Lm5ldHdvcmspPC1jKCJSZWd1bGF0b3IiLCJUYXJnZXQiLCJJbnRlcmFjdGlvbiIpCm91dHB1dC5uZXR3b3JrCn0Kc1JOQXMubmV0d29yazwtY3JlYXRlLm5ldHdvcmsoc1JOQXMscmVjb3ZlcmVkLmludGVyYWN0aW9ucy5tYXRyaXgsbm92ZWwuaW50ZXJhY3Rpb25zLm1hdHJpeCkKc1JOQS5uZXR3b3JrLmlncmFwaC5mb3JtYXQ8LWdyYXBoX2Zyb21fZGF0YV9mcmFtZShzUk5Bcy5uZXR3b3JrWyxjKCJSZWd1bGF0b3IiLCJUYXJnZXQiKV0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAsdW5pb24oc1JOQXMubmV0d29ya1ssIlJlZ3VsYXRvciJdLHNSTkFzLm5ldHdvcmtbLCJUYXJnZXQiXSksIGRpcmVjdGVkID0gVCkKc2VsZWN0ZWQubmV0d29yay5sYXlvdXQgPC0gbGF5b3V0X25pY2VseShzUk5BLm5ldHdvcmsuaWdyYXBoLmZvcm1hdCkKcGxvdChzUk5BLm5ldHdvcmsuaWdyYXBoLmZvcm1hdCxsYXlvdXQgPSBzZWxlY3RlZC5uZXR3b3JrLmxheW91dCwgZWRnZS5hcnJvdy5zaXplID0wLjIsdmVydGV4LmxhYmVsLmNleD0wLjMsdmVydGV4LnNpemU9OSxtYWluPSJGaWcgM0IgZHJhZnQiKQpgYGAKMmMuIENvbXBhcmUgdGhlIHJlZ3Jlc3Npb24gY29lZmZpY2llbnRzIChiZXRhcykgb2Ygc1JOQS1tUk5BIGFuZCBURi1nZW5lIGludGVyYWN0aW9ucyAoRmlnIDNDKQpgYGB7cn0KYmV0YXMudGZzPC1jKCkKYmV0YXMuc1JOQXM8LWMoKQojU2F2ZSBURnMgbmFtZXMKVEZzPC1zZXRkaWZmKGNvbG5hbWVzKG5vcm1hbGl6ZWQuY29uZmlkZW5jZS5tYXRyaXgpLHNSTkFzKQojQ29tYmluZWQgcmVjb3ZlcmVkIGFuZCBub3ZlbCBpbnRlcmFjdGlvbnMgaW4gYSBzaW5nbGUgbWF0cml4CmFsbC5wcmVkaWN0aW9ucy5tYXRyaXg8LXJlY292ZXJlZC5pbnRlcmFjdGlvbnMubWF0cml4ICsgbm92ZWwuaW50ZXJhY3Rpb25zLm1hdHJpeApiZXRhcy50ZnM8LWFicyhjb21iaW5lZC5iZXRhc1ssVEZzXVt3aGljaChhbGwucHJlZGljdGlvbnMubWF0cml4WyxURnNdIT0wKV0pCmJldGFzLnNSTkFzPC1hYnMoY29tYmluZWQuYmV0YXNbLHNSTkFzXVt3aGljaChhbGwucHJlZGljdGlvbnMubWF0cml4WyxzUk5Bc10hPTApXSkKdGVtcG9yYWwubWF0cml4PC1yYmluZChjYmluZChiZXRhcy50ZnMscmVwKCJURnMiLGxlbmd0aChiZXRhcy50ZnMpKSksY2JpbmQoYmV0YXMuc1JOQXMscmVwKCJzUk5BcyIsbGVuZ3RoKGJldGFzLnNSTkFzKSkpKQpjb2xuYW1lcyh0ZW1wb3JhbC5tYXRyaXgpPC1jKCJCZXRhcyIsIlR5cGUiKQp0ZW1wb3JhbC5tYXRyaXg8LWFzLmRhdGEuZnJhbWUodGVtcG9yYWwubWF0cml4KQp0ZW1wb3JhbC5tYXRyaXgkQmV0YXM8LWFzLm51bWVyaWMoYXMudmVjdG9yKHRlbXBvcmFsLm1hdHJpeCRCZXRhcykpCnAgPC0gZ2dwbG90KHRlbXBvcmFsLm1hdHJpeCwgYWVzKHg9VHlwZSwgeT1CZXRhcyxmaWxsPVR5cGUpKSArIGdlb21fdmlvbGluKHNob3cubGVnZW5kID0gRikKcCArIHN0YXRfc3VtbWFyeShmdW4ueT1tZWRpYW4sIGdlb209InBvaW50Iiwgc2l6ZT0yLHNob3cubGVnZW5kID0gRikgKyBjb29yZF9mbGlwKCkKYGBgCjJkLiBQbG90IGV4cGVyaW1lbnRhbCBzdXBwb3J0IG9mIHRoZSBpbmZlcnJlZCBFLiBjb2xpIHNSTkEgcmVndWxvbnMgKEZpZyAzRCkKYGBge3J9CiNUaGlzIGZpZ3VyZSBpcyBnZW5lcmF0ZWQgdXNpbmcgZGF0YSBpbiBTdXBwbGVtZW50YXJ5IERhdGFzZXQgMQphY2N1cmFjeS5zUk5BLnJlZ3Vsb25zPC1jKCkKYWNjdXJhY3kuQ3lhUi5yZWd1bG9uPC1jYmluZChjKDYsMSw3LDApLGMoMCw0LDQsMCkpIAphY2N1cmFjeS5zUk5BLnJlZ3Vsb25zPC1yYmluZChhY2N1cmFjeS5zUk5BLnJlZ3Vsb25zLGFjY3VyYWN5LkN5YVIucmVndWxvbikKYWNjdXJhY3kuRm5yUy5yZWd1bG9uPC1jYmluZChjKDcsMSw4LDApLGMoMCw2LDYsMCkpCmFjY3VyYWN5LnNSTkEucmVndWxvbnM8LXJiaW5kKGFjY3VyYWN5LnNSTkEucmVndWxvbnMsYWNjdXJhY3kuRm5yUy5yZWd1bG9uKQphY2N1cmFjeS5HY3ZCLnJlZ3Vsb248LWNiaW5kKGMoNiwxNiwyMiwwKSxjKDAsMTEsMTEsMCkpCmFjY3VyYWN5LnNSTkEucmVndWxvbnM8LXJiaW5kKGFjY3VyYWN5LnNSTkEucmVndWxvbnMsYWNjdXJhY3kuR2N2Qi5yZWd1bG9uKQphY2N1cmFjeS5PbXJBLnJlZ3Vsb248LWNiaW5kKGMoNCwxLDUsMCksYygwLDAsMCwwKSkKYWNjdXJhY3kuc1JOQS5yZWd1bG9uczwtcmJpbmQoYWNjdXJhY3kuc1JOQS5yZWd1bG9ucyxhY2N1cmFjeS5PbXJBLnJlZ3Vsb24pCmFjY3VyYWN5LlJ5YkIucmVndWxvbjwtY2JpbmQoYyg1LDAsNSwwKSxjKDAsMywzLDApKQphY2N1cmFjeS5zUk5BLnJlZ3Vsb25zPC1yYmluZChhY2N1cmFjeS5zUk5BLnJlZ3Vsb25zLGFjY3VyYWN5LlJ5YkIucmVndWxvbikKYWNjdXJhY3kuUnloQi5yZWd1bG9uPC1jYmluZChjKDYsNSwxMSwwKSxjKDAsOCw4LDApKQphY2N1cmFjeS5zUk5BLnJlZ3Vsb25zPC1yYmluZChhY2N1cmFjeS5zUk5BLnJlZ3Vsb25zLGFjY3VyYWN5LlJ5aEIucmVndWxvbikKYWNjdXJhY3kuU3BvdDQyLnJlZ3Vsb248LWNiaW5kKGMoNCw1LDksMCksYygwLDAsMCwwKSkKYWNjdXJhY3kuc1JOQS5yZWd1bG9uczwtcmJpbmQoYWNjdXJhY3kuc1JOQS5yZWd1bG9ucyxhY2N1cmFjeS5TcG90NDIucmVndWxvbikKI0NyZWF0ZSBiYXJwbG90CmJhcnBsb3QodChhY2N1cmFjeS5zUk5BLnJlZ3Vsb25zKSxjb2w9cmVwKGMocmdiKDkwLDE4MCwxNzIsbWF4Q29sb3JWYWx1ZSA9IDI1NSkscmdiKDIxNiwxNzksMTAxLG1heENvbG9yVmFsdWUgPSAyNTUpKSwyOCkKICAgICAgICAsbmFtZXM9cmVwKGMoIktub3duIiwiTm92ZWwiLCJGdWxsIiwiIiksNyksbGFzPTIsY2V4LmF4aXMgPSAxLjI1LHlsYWI9IiMgVGFyZ2V0cyIpCmxlZ2VuZCgidG9wbGVmdCIsIAogICAgICAgbGVnZW5kID0gYygiU3VwcG9ydGVkIiwgIk5vdCBTdXBwb3J0ZWQiKSwgCiAgICAgICBmaWxsID0gYyhyZ2IoOTAsMTgwLDE3MixtYXhDb2xvclZhbHVlID0gMjU1KSxyZ2IoMjE2LDE3OSwxMDEsbWF4Q29sb3JWYWx1ZSA9IDI1NSkpLGJ0eT0ibiIpCmBgYAoyZS4gUGxvdCBwZXJmb3JtYW5jZSBvZiB0aGUgSW5mZXJlbGF0b3Igd2l0aCBub2lzeSBzUk5BIHByaW9ycyAoRmlnIDNFICYgRmlnIFMyKSAKYGBge3J9CiNMb2FkIEluZmVyZWxhdG9yIHJ1biB3aXRob3V0IG5vaXN5IHNSTkEgcHJpb3JzCmxvYWQoIi4uL0luZmVyZWxhdG9yX291dHB1dF9maWxlcy9FY29saV84c1JOQXMvYmV0YXNfZnJhY190cF8xMDBfcGVybV8xLS1mcmFjX2ZwXzBfcGVybV8xXzEuMS5SRGF0YSIpCmxvYWQoIi4uL0luZmVyZWxhdG9yX291dHB1dF9maWxlcy9FY29saV84c1JOQXMvY29tYmluZWRjb25mX2ZyYWNfdHBfMTAwX3Blcm1fMS0tZnJhY19mcF8wX3Blcm1fMV8xLjEuUkRhdGEiKQpsb2FkKCIuLi9JbmZlcmVsYXRvcl9vdXRwdXRfZmlsZXMvRWNvbGlfOHNSTkFzL3BhcmFtc19hbmRfaW5wdXQuUkRhdGEiKQojQ3JlYXRlIGZpbmFsIG1vZGVsCnNvdXJjZSgiLi4vTWlzY2VsbGFuZW91c19zY3JpcHRzL2NyZWF0ZV9maW5hbF9uZXR3b3Jrcy5SIikKI1NhdmUgbWFudWFsbHkgc2VsZWN0ZWQgc1JOQSBwcmlvcnMgdXNlZCBhcyBpbnB1dCBmb3IgdGhlIEluZmVyZWxhdG9yCm9yaWdpbmFsLnNSTkFzLmdzPC1JTiRwcmlvcnMubWF0WyxzUk5Bc10KI1JlY292ZXJlZCBzUk5BIHByaW9ycyBpbiB0aGUgSW5mZXJlbGF0b3IgcnVuIHdpdGhvdXQgbm9pc3kgcHJpb3JzCnJlY292ZXJlZC5zUk5BLnByaW9ycy5uby5ub2lzZTwtcmVjb3ZlcmVkLmludGVyYWN0aW9ucy5tYXRyaXhbLHNSTkFzXQojVGhlIHJhdGlvIG9mIHRydWU6ZmFsc2UgcmF0aW8gaW4gdGhlIG5vaXN5IHNSTkEgcHJpb3JzICgxOjEsMToyLDE6NSkKbm9pc2UubGV2ZWw8LWMoMSwyLDUpCiNDcmVhdGUgbWF0cml4IHRvIHN0b3JlIGF2ZXJhZ2UgZXhwZXJpbWVudGFsIHN1cHBvcnQgcmF0ZSBvZiByZWNvdmVyZWQgc1JOQSBwcmlvcnMKbWVhbi5zdXBwb3J0LnJhdGUucmVjb3ZlcmVkLnByaW9ycy5tYXRyaXg8LW1hdHJpeChucm93PTMsbmNvbD1sZW5ndGgoc1JOQXMpKzEsMCxkaW1uYW1lcyA9IGxpc3QocGFzdGUoIm4iLG5vaXNlLmxldmVsLHNlcD0iIiksYyhzUk5BcywiUmFuZG9tIikpKQojVGhlIGV4cGVjdGVkIGF2ZXJhZ2UgcmF0aW8gZnJvbSAgcmFuZG9tIHNlbGVjdGlvbnMKbWVhbi5zdXBwb3J0LnJhdGUucmVjb3ZlcmVkLnByaW9ycy5tYXRyaXhbLDldPC1jKDEvMiwxLzMsMS82KQojQ3JlYXRlIG1hdHJpeCB0byBzdG9yZSBhdmVyYWdlIG51bWJlciBvZiByZWNvdmVyZWQgc1JOQSBwcmlvcnMKbWVhbi5udW1iZXIucmVjb3ZlcmVkLnByaW9yczwtbWF0cml4KG5yb3c9MyxuY29sPWxlbmd0aChzUk5BcyksMCxkaW1uYW1lcyA9IGxpc3QocGFzdGUoIm4iLG5vaXNlLmxldmVsLHNlcD0iIiksc1JOQXMpKQojQ3JlYXRlIG1hdHJpeCB0byBzdG9yZSBhdmVyYWdlIG51bWJlciBvZiBleHBlcmltZW50YWxseSBzdXBwb3J0ZWQgcmVjb3ZlcmVkIHNSTkEgcHJpb3JzCm1lYW4ubnVtYmVyLnRydWUucmVjb3ZlcmVkLnByaW9yczwtbWF0cml4KG5yb3c9MyxuY29sPWxlbmd0aChzUk5BcyksMCxkaW1uYW1lcyA9IGxpc3QocGFzdGUoIm4iLG5vaXNlLmxldmVsLHNlcD0iIiksc1JOQXMpKQojVGhpcyBsb29wIGNvbXB1dGVzIHRoZSBudW1iZXIgb2YgcmVjb3ZlcmVkIHByaW9ycyBhbmQgdGhlIGV4cC4gc3VwcG9ydCByYXRlIG9mIHRoZSByZWNvdmVyZWQgcHJpb3JzIGZvciB0aGUgSW5mZXJlbGF0b3IgcnVucyB0aGF0IHVzZWQgbm9pc3kgc1JOQSBwcmlvcnMgKHRlbiBydW5zIGZvciBlYWNoIG5vaXNlIGxldmVsKSAgCmZvcihrIGluIG5vaXNlLmxldmVsKQp7CiAgI0NyZWF0ZSBtYXRyaWNlcyB0byBzdG9yZSB0aGUgaW5mb3JtYXRpb24gb2YgdGhlIHRlbiBJbmZlcmVsYXRvciBydW5zIAogIHRlbXBvcmFsLnJlY292ZXJlZC5zUk5BLnByaW9ycy5tYXRyaXg8LW1hdHJpeChucm93PTEwLG5jb2w9bGVuZ3RoKHNSTkFzKSwwLGRpbW5hbWVzID0gbGlzdChwYXN0ZSgiciIsMToxMCxzZXA9IiIpLHNSTkFzKSkKICB0ZW1wb3JhbC5yZWNvdmVyZWQudHJ1ZS5zUk5BLnByaW9ycy5tYXRyaXg8LW1hdHJpeChucm93PTEwLG5jb2w9bGVuZ3RoKHNSTkFzKSwwLGRpbW5hbWVzID0gbGlzdChwYXN0ZSgiciIsMToxMCxzZXA9IiIpLHNSTkFzKSkKICB0ZW1wb3JhbC5zdXBwcG9ydC5yYXRlLnJlY292ZXJlZC5zUk5BLnByaW9ycy5tYXRyaXg8LW1hdHJpeChucm93PTEwLG5jb2w9bGVuZ3RoKHNSTkFzKSwwLGRpbW5hbWVzID0gbGlzdChwYXN0ZSgiciIsMToxMCxzZXA9IiIpLHNSTkFzKSkKICAKICBmb3IociBpbiAxOjEwKQogIHsKICBwYXRoLnRvLm5vaXN5LmluZmVyZWxhdG9yLm91dHB1dDwtIi4uL0luZmVyZWxhdG9yX291dHB1dF9maWxlcy9FY29saV9ub2lzeV9zUk5BX3ByaW9ycy9lY29fc1JOQV9zdHJvbmdfbTNGX3VuYXZlcmFnZWRfbm9pc3lQcmlvcnNfbiIKICBsb2FkKHBhc3RlKHBhdGgudG8ubm9pc3kuaW5mZXJlbGF0b3Iub3V0cHV0LGssIl9yIixyLCIvY29tYmluZWRjb25mX2ZyYWNfdHBfMTAwX3Blcm1fMS0tZnJhY19mcF8wX3Blcm1fMV8xLjEuUkRhdGEiLHNlcD0iIikpCiAgbG9hZChwYXN0ZShwYXRoLnRvLm5vaXN5LmluZmVyZWxhdG9yLm91dHB1dCxrLCJfciIsciwiL2JldGFzX2ZyYWNfdHBfMTAwX3Blcm1fMS0tZnJhY19mcF8wX3Blcm1fMV8xLjEuUkRhdGEiLHNlcD0iIikpCiAgbG9hZChwYXN0ZShwYXRoLnRvLm5vaXN5LmluZmVyZWxhdG9yLm91dHB1dCxrLCJfciIsciwiL3BhcmFtc19hbmRfaW5wdXQuUkRhdGEiLHNlcD0iIikpCiAgc291cmNlKCIuLi9NaXNjZWxsYW5lb3VzX3NjcmlwdHMvY3JlYXRlX2ZpbmFsX25ldHdvcmtzLlIiKQogIGZvcihzIGluIHNSTkFzKQogIHsKICAgIHRydWUuc1JOQS5wcmlvcnM8LW5hbWVzKHdoaWNoKG9yaWdpbmFsLnNSTkFzLmdzWyxzXSE9MCkpCiAgICAjVGhlIGN1cmF0ZWQuZ3MubWF0cml4IG9iamVjdCB3YXMgY3JlYXRlZCBieSB0aGUgY3JlYXRlX2ZpbmFsX25ldHdvcmtzLlIgc2NyaXB0IHVzZWQgYWJvdmUKICAgIG5vaXN5LnNSTkEucHJpb3JzPC1uYW1lcyh3aGljaChjdXJhdGVkLmdzLm1hdHJpeFssc10hPTApKQogICAgI1RoZSByZWNvdmVyZWQuc1JOQS5wcmlvcnMgb2JqZWN0IHdhcyBjcmVhdGVkIGJ5IHRoZSBjcmVhdGVfZmluYWxfbmV0d29ya3MuUiBzY3JpcHQgdXNlZCBhYm92ZQogICAgcmVjb3ZlcmVkLnNSTkEucHJpb3JzPC1uYW1lcyh3aGljaChyZWNvdmVyZWQuaW50ZXJhY3Rpb25zLm1hdHJpeFssc10hPTApKQogICAgdGVtcG9yYWwucmVjb3ZlcmVkLnNSTkEucHJpb3JzLm1hdHJpeFtwYXN0ZSgiciIscixzZXA9IiIpLHNdPC1sZW5ndGgocmVjb3ZlcmVkLnNSTkEucHJpb3JzKQogICAgdGVtcG9yYWwucmVjb3ZlcmVkLnRydWUuc1JOQS5wcmlvcnMubWF0cml4W3Bhc3RlKCJyIixyLHNlcD0iIiksc108LWxlbmd0aChpbnRlcnNlY3QocmVjb3ZlcmVkLnNSTkEucHJpb3JzLHRydWUuc1JOQS5wcmlvcnMpKQogICAgdGVtcG9yYWwuc3VwcHBvcnQucmF0ZS5yZWNvdmVyZWQuc1JOQS5wcmlvcnMubWF0cml4W3Bhc3RlKCJyIixyLHNlcD0iIiksc108LXRlbXBvcmFsLnJlY292ZXJlZC50cnVlLnNSTkEucHJpb3JzLm1hdHJpeFtwYXN0ZSgiciIscixzZXA9IiIpLHNdL2xlbmd0aChyZWNvdmVyZWQuc1JOQS5wcmlvcnMpCiAgfQogIH0KICAjQ29tcHV0ZSBhdmVyYWdlIGFjcnJvcyB0aGUgdGVuIHJ1bnMKICBtZWFuLm51bWJlci5yZWNvdmVyZWQucHJpb3JzW3Bhc3RlKCJuIixrLHNlcD0iIiksMTo4XTwtY29sTWVhbnModGVtcG9yYWwucmVjb3ZlcmVkLnNSTkEucHJpb3JzLm1hdHJpeCxuYS5ybSA9IFQpCiAgbWVhbi5udW1iZXIudHJ1ZS5yZWNvdmVyZWQucHJpb3JzW3Bhc3RlKCJuIixrLHNlcD0iIiksMTo4XTwtY29sTWVhbnModGVtcG9yYWwucmVjb3ZlcmVkLnRydWUuc1JOQS5wcmlvcnMubWF0cml4LG5hLnJtPVQpCiAgbWVhbi5zdXBwb3J0LnJhdGUucmVjb3ZlcmVkLnByaW9ycy5tYXRyaXhbcGFzdGUoIm4iLGssc2VwPSIiKSwxOjhdPC1jb2xNZWFucyh0ZW1wb3JhbC5zdXBwcG9ydC5yYXRlLnJlY292ZXJlZC5zUk5BLnByaW9ycy5tYXRyaXgsbmEucm09VCkKfQpwYXIobWZyb3c9YygxLDEpKQpib3hwbG90KHlsaW09YygwLDEpLHQobWVhbi5zdXBwb3J0LnJhdGUucmVjb3ZlcmVkLnByaW9ycy5tYXRyaXgpLGNvbD0id2hpdGUiLG91dGxpbmU9Rixib3hsdHk9MCx3aGlza2x0eSA9IDAsIHN0YXBsZWx0eSA9IDAsIG5hbWVzPWMoIjE6MSIsIjE6MiIsIjE6NSIpLGZyYW1lPUYsCiAgeGxhYj0iU3VwcG9ydGVkIDogVW5zdXBwb3J0ZWQgcHJpb3JzIix5bGFiPSJQcm9wb3J0aW9uIG9mIHJlY292ZXJlZCBwcmlvcnMgdy8gc3VwcG9ydCIsY2V4LmxhYj0xLjEsbWFpbj0iRmlnIDNFIikKZG90cy5jb2xvcnM8LWMoImJsdWUiLCJyZWQiLCJkYXJrIGdyZWVuIiwiZGVlcHBpbmsiLCJvcmFuZ2UiLCJjeWFuIiwicHVycGxlIiwiYnJvd24iLCJncmF5IikKZG90cy5zaGFwZXM8LWMoMiwxLDM6NiwwLDcsOCkKZm9yKHIgaW4gMToobGVuZ3RoKHNSTkFzKSsxKSkKewogcG9pbnRzKHk9bWVhbi5zdXBwb3J0LnJhdGUucmVjb3ZlcmVkLnByaW9ycy5tYXRyaXhbLHJdLHg9YygxLDIsMykscGNoPWRvdHMuc2hhcGVzW3JdLGNvbD1kb3RzLmNvbG9yc1tyXSkKfQpsZWdlbmQoImJvdHRvbWxlZnQiLGluc2V0PTAuMDMsYm94Lmx0eT0wLjEsYm94Lmx3ZD0wLjIsCiAgYygiUnloQigxMikiLCJTcG90NDIoMTIpIiwiR2N2Qig5KSIsIk1pY0EoMTApIiwiT21yQSg2KSIsIkN5YVIoNikiLCJSeWJCKDEwKSIsIkZuclMoMTApIiwiUmFuZG9tIiksY29sPWRvdHMuY29sb3JzLGNleD0wLjY1LHBjaD1kb3RzLnNoYXBlcykKI0NyZWF0ZSBGaWcgUzIgKGJlY2F1c2UgTWljQSB0YXJnZXRzIHdlcmUgbm90IHByZWRpY3RlZCBpbiB0aGUgb3JpZ2luYWwgcnVuLSB3ZSByZW1vdmUgTWljQSBmcm9tIHRoZSBmb2xsb3dpbmcgYW5hbHlzaXMpCnNSTkFzLmZpZ1MyPC1zUk5Bc1stNF0KcGFyKG1mcm93PWMoMSwyKSkKI1BhbmVsIEEKYm94cGxvdCh5bGltPWMoMCwxLjIpLHQobWVhbi5udW1iZXIucmVjb3ZlcmVkLnByaW9yc1ssc1JOQXMuZmlnUzJdKS9jb2xTdW1zKGFicyhyZWNvdmVyZWQuc1JOQS5wcmlvcnMubm8ubm9pc2VbLHNSTkFzLmZpZ1MyXSkpLGNvbD0id2hpdGUiLG91dGxpbmU9Rixib3hsdHk9MCx3aGlza2x0eSA9IDAsIHN0YXBsZWx0eSA9IDAsIG5hbWVzPWMoIjE6MSIsIjE6MiIsIjE6NSIpLGZyYW1lPUYseGxhYj0iU3VwcG9ydGVkIDogVW5zdXBwb3J0ZWQgcHJpb3JzIix5bGFiPSJUb3RhbCByZWNvdmVyZWQgcHJpb3JzIChjb21wYXJlZCB0byBydW4gdy9vdXQgZmFsc2UgcHJpb3JzKSIsY2V4LmxhYj0xLjEsbWFpbj0iRmlnIFMyQSIpCmZvcih4IGluIDE6KGxlbmd0aChzUk5Bcy5maWdTMikpKQp7CiBwb2ludHMoeT1tZWFuLm51bWJlci5yZWNvdmVyZWQucHJpb3JzWyxzUk5Bcy5maWdTMlt4XV0vc3VtKGFicyhyZWNvdmVyZWQuc1JOQS5wcmlvcnMubm8ubm9pc2VbLHNSTkFzLmZpZ1MyW3hdXSkpLHg9YygxLDIsMykscGNoPWRvdHMuc2hhcGVzWy00XVt4XSxjb2w9ZG90cy5jb2xvcnNbLTRdW3hdKQp9CiNQYW5lbCBCCmJveHBsb3QoeWxpbT1jKDAsMS4yKSx0KG1lYW4ubnVtYmVyLnRydWUucmVjb3ZlcmVkLnByaW9yc1ssc1JOQXMuZmlnUzJdKS9jb2xTdW1zKGFicyhyZWNvdmVyZWQuc1JOQS5wcmlvcnMubm8ubm9pc2VbLHNSTkFzLmZpZ1MyXSkpLGNvbD0id2hpdGUiLG91dGxpbmU9Rixib3hsdHk9MCx3aGlza2x0eSA9IDAsIHN0YXBsZWx0eSA9IDAsIG5hbWVzPWMoIjE6MSIsIjE6MiIsIjE6NSIpLGZyYW1lPUYseGxhYj0iU3VwcG9ydGVkIDogVW5zdXBwb3J0ZWQgcHJpb3JzIix5bGFiPSJUcnVlIHJlY292ZXJlZCBwcmlvcnMgKGNvbXBhcmVkIHRvIG5vIGZhbHNlIHByaW9ycyBydW4pIixjZXgubGFiPTEuMSxtYWluPSJGaWcgUzJCIikKZm9yKHggaW4gMToobGVuZ3RoKHNSTkFzLmZpZ1MyKSkpCnsKIHBvaW50cyh5PW1lYW4ubnVtYmVyLnRydWUucmVjb3ZlcmVkLnByaW9yc1ssc1JOQXMuZmlnUzJbeF1dL3N1bShhYnMocmVjb3ZlcmVkLnNSTkEucHJpb3JzLm5vLm5vaXNlWyxzUk5Bcy5maWdTMlt4XV0pKSx4PWMoMSwyLDMpLHBjaD1kb3RzLnNoYXBlc1stNF1beF0sY29sPWRvdHMuY29sb3JzWy00XVt4XSkKfQpsZWdlbmQoInRvcHJpZ2h0IixpbnNldD0wLjAzLGJveC5sdHk9MC4xLGJveC5sd2Q9MC4yLAogIGMoIlJ5aEIoMTIpIiwiU3BvdDQyKDEyKSIsIkdjdkIoOSkiLCJPbXJBKDYpIiwiQ3lhUig2KSIsIlJ5YkIoMTApIiwiRm5yUygxMCkiKSxjZXg9MC42NSxwY2g9ZG90cy5zaGFwZXNbMTo4XVstNF0sY29sPWRvdHMuY29sb3JzWzE6OF1bLTRdKQpgYGAKMy4gSW5zcGVjdCBzUk5BIHJlZ3Vsb25zIGluZmVycmVkIHVzaW5nIENvcHJhUk5BIChXcmlndGggZXQgYWwuIDIwMTMpIHNSTkEgcHJpb3JzIChGaWcgNCkKYGBge3J9CiNDcmVhdGUgRmlnIDRCIHVzaW5nIFRhYmxlIFMyCmNvcHJhUk5BLjEwMC5zdXBwb3J0LnJhdGU8LWMoLjI5LC4zLC4xNykKY29wcmFSTkEuMTAwLnJlY292ZXJlZC5wcmlvcnMuc3VwcG9ydC5yYXRlPC1jKDEsLjY3LC4zMykKY29wcmFSTkEucHZhbC5zdXBwb3J0LnJhdGU8LWMoLjM1LC40NiwuMjIpCmNvcHJhUk5BLnB2YWwucmVjb3ZlcmVkLnByaW9ycy5zdXBwb3J0LnJhdGU8LWMoLjQsLjgyLC4yNSkKY29wcmFSTkEuZW5yaWNoZWQuc3VwcG9ydC5yYXRlPC1jKC41LC41NiwuMjYpCmNvcHJhUk5BLmVucmljaGVkLnJlY292ZXJlZC5wcmlvcnMuc3VwcG9ydC5yYXRlPC1jKDEsLjgyLC40KQpjb3ByYVJOQS50b3AxNS5zdXBwb3J0LnJhdGU8LWMoLjQ4LC42NCwuMzEpCmNvcHJhUk5BLnRvcDE1LnJlY292ZXJlZC5wcmlvcnMuc3VwcG9ydC5yYXRlPC1jKDEsLjgsLjUpCmNvcHJhUk5BLkFORC5zdXBwb3J0LnJhdGU8LWMoLjU1LC43MywuMzUpCmNvcHJhUk5BLkFORC5yZWNvdmVyZWQucHJpb3JzLnN1cHBvcnQucmF0ZTwtYygxLC43NywuNjcpCmNvcHJhUk5BLk9SLnN1cHBvcnQucmF0ZTwtYyguMzcsLjQxLC4yKQpjb3ByYVJOQS5PUi5yZWNvdmVyZWQucHJpb3JzLnN1cHBvcnQucmF0ZTwtYygxLC44LC4yOSkKY29wcmFSTkEuc3VwcG9ydC5yYXRlPC1jKGNvcHJhUk5BLjEwMC5zdXBwb3J0LnJhdGUsY29wcmFSTkEucHZhbC5zdXBwb3J0LnJhdGUsY29wcmFSTkEuZW5yaWNoZWQuc3VwcG9ydC5yYXRlLAogICAgICAgICAgICAgICAgICAgICAgICAgY29wcmFSTkEudG9wMTUuc3VwcG9ydC5yYXRlLGNvcHJhUk5BLkFORC5zdXBwb3J0LnJhdGUsY29wcmFSTkEuT1Iuc3VwcG9ydC5yYXRlKQpjb3ByYVJOQS5yZWNvdmVyZWQucHJpb3JzLnN1cHBvcnQucmF0ZTwtYyhjb3ByYVJOQS4xMDAucmVjb3ZlcmVkLnByaW9ycy5zdXBwb3J0LnJhdGUsY29wcmFSTkEucHZhbC5yZWNvdmVyZWQucHJpb3JzLnN1cHBvcnQucmF0ZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29wcmFSTkEuZW5yaWNoZWQucmVjb3ZlcmVkLnByaW9ycy5zdXBwb3J0LnJhdGUsY29wcmFSTkEudG9wMTUucmVjb3ZlcmVkLnByaW9ycy5zdXBwb3J0LnJhdGUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvcHJhUk5BLkFORC5yZWNvdmVyZWQucHJpb3JzLnN1cHBvcnQucmF0ZSxjb3ByYVJOQS5PUi5yZWNvdmVyZWQucHJpb3JzLnN1cHBvcnQucmF0ZSkKCnBsb3QoeD1jb3ByYVJOQS5zdXBwb3J0LnJhdGUseT1jb3ByYVJOQS5yZWNvdmVyZWQucHJpb3JzLnN1cHBvcnQucmF0ZSxjb2w9cmVwKGMoInB1cnBsZSIsImdyZWVuIiwib3JhbmdlIiksNikseGxhYj0iRXhwZXJpbWVudGFsIHN1cHBvcnQgcmF0ZSAtIENvcHJhUk5BIHByaW9ycyIseWxhYj0iRXhwZXJpbWVudGFsIHN1cHBvcnQgcmF0ZSAtIFJlY292ZXJlZCBwcmlvcnMiLHhsaW09YygwLDEpLHlsaW09YygwLDEpLAogICAgIHBjaD1yZXAoYygxNSwxNiwxNywxOCwxOSw0KSxlYWNoPTMpKQpsaW5lcyh4PWMoMCwxKSx5PWMoMCwxKSxjb2w9InJlZCIsbHR5PTIpCmxlZ2VuZCgnYm90dG9tcmlnaHQnLCBjKCJSeWhCIiwiR2N2QiIsIlNwb3QgNDIiKSwgY29sPWMoInB1cnBsZSIsImdyZWVuIiwib3JhbmdlIikscGNoPTE2LGJ0eT0ibiIpCiNQbG90IHRoZSBpbmZlcnJlZCBSeWhCIHJlZ3Vsb24gd2hlbiBDb3ByYVJOQSBwcmVkaWN0aW9ucyBhc3NvY2lhdGVkIHdpdGggZW5yaWNoZWQgZnVuY3Rpb25hbCB0ZXJtcyB3ZXJlIHVzZWQgYXMgcHJpb3JzIChGaWcgNEMpCiNIZXJlIHdlIHVzZSB0aGUgaWdyYXBoIHBhY2thZ2UgdG8gZ2V0ICByYXcgZHJhZnRzCiNMb2FkIHRoZSBvdXRwdXQgZmlsZXMgb2YgdGhlIGNvcnJlc3BvbmRpbmcgSW5mZXJlbGF0b3IgcnVuCmxvYWQoIi4uL0luZmVyZWxhdG9yX291dHB1dF9maWxlcy9FY29saV9Db3ByYVJOQV9zUk5BX3ByaW9ycy9yeWhCX3NpbGljb18yX0JCU1JfMS4xXzEwMF8wL2JldGFzX2ZyYWNfdHBfMTAwX3Blcm1fMS0tZnJhY19mcF8wX3Blcm1fMV8xLjEuUkRhdGEiKQpsb2FkKCIuLi9JbmZlcmVsYXRvcl9vdXRwdXRfZmlsZXMvRWNvbGlfQ29wcmFSTkFfc1JOQV9wcmlvcnMvcnloQl9zaWxpY29fMl9CQlNSXzEuMV8xMDBfMC9jb21iaW5lZGNvbmZfZnJhY190cF8xMDBfcGVybV8xLS1mcmFjX2ZwXzBfcGVybV8xXzEuMS5SRGF0YSIpCmxvYWQoIi4uL0luZmVyZWxhdG9yX291dHB1dF9maWxlcy9FY29saV9Db3ByYVJOQV9zUk5BX3ByaW9ycy9yeWhCX3NpbGljb18yX0JCU1JfMS4xXzEwMF8wL3BhcmFtc19hbmRfaW5wdXQuUkRhdGEiKQojQ3JlYXRlIGZpbmFsIG5ldHdvcmsgbW9kZWwKc291cmNlKCIuLi9NaXNjZWxsYW5lb3VzX3NjcmlwdHMvY3JlYXRlX2ZpbmFsX25ldHdvcmtzLlIiKQojU2F2ZSB0aGUgaW5mZXJyZWQgUnloQiByZWd1bG9uClJ5aEIucmVndWxvbjwtY3JlYXRlLm5ldHdvcmsoInJ5aEJfYjQ0NTFfNCIscmVjb3ZlcmVkLmludGVyYWN0aW9ucy5tYXRyaXgsbm92ZWwuaW50ZXJhY3Rpb25zLm1hdHJpeCkKUnloQi5yZWd1bG9uLmlncmFwaC5mb3JtYXQ8LWdyYXBoX2Zyb21fZGF0YV9mcmFtZShSeWhCLnJlZ3Vsb25bLDE6Ml0sIHVuaW9uKFJ5aEIucmVndWxvblssIlJlZ3VsYXRvciJdLFJ5aEIucmVndWxvblssIlRhcmdldCJdKSwgZGlyZWN0ZWQgPSBUKQpwbG90KFJ5aEIucmVndWxvbi5pZ3JhcGguZm9ybWF0LGxheW91dCA9IGxheW91dF9uaWNlbHkoUnloQi5yZWd1bG9uLmlncmFwaC5mb3JtYXQpLCBlZGdlLmFycm93LnNpemUgPTAuNCx2ZXJ0ZXgubGFiZWwuY2V4PTEsdmVydGV4LnNpemU9MzAsbWFpbj0iRmlnIDRDIix2ZXJ0ZXguc2hhcGU9Yygic3F1YXJlIixyZXAoImNpcmNsZSIsbnJvdyhSeWhCLnJlZ3Vsb24pKSksdmVydGV4LmxhYmVsLmNvbG9yPWMoImJsdWUiLHJlcCgiYmxhY2siLGxlbmd0aChncmVwKCJwcmlvciIsUnloQi5yZWd1bG9uWywzXSkpKSxyZXAoIndoaXRlIixsZW5ndGgoZ3JlcCgibm92ZWwiLFJ5aEIucmVndWxvblssM10pKSkpKQojUGxvdCB0aGUgaW5mZXJyZWQgR2N2QiByZWd1bG9uIHdoZW4gQ29wcmFSTkEgcHJlZGljdGlvbnMgd2l0aCBwLXZhbHVlIDw9IDAuMDEgd2VyZSB1c2VkIGFzIHByaW9ycyAoRmlnIDREKQojTG9hZCB0aGUgb3V0cHV0IGZpbGVzIG9mIHRoZSBjb3JyZXNwb25kaW5nIEluZmVyZWxhdG9yIHJ1bgpsb2FkKCIuLi9JbmZlcmVsYXRvcl9vdXRwdXRfZmlsZXMvRWNvbGlfQ29wcmFSTkFfc1JOQV9wcmlvcnMvZ2N2Ql9zaWxpY29fMV9CQlNSXzEuMV8xMDBfMC9iZXRhc19mcmFjX3RwXzEwMF9wZXJtXzEtLWZyYWNfZnBfMF9wZXJtXzFfMS4xLlJEYXRhIikKbG9hZCgiLi4vSW5mZXJlbGF0b3Jfb3V0cHV0X2ZpbGVzL0Vjb2xpX0NvcHJhUk5BX3NSTkFfcHJpb3JzL2djdkJfc2lsaWNvXzFfQkJTUl8xLjFfMTAwXzAvY29tYmluZWRjb25mX2ZyYWNfdHBfMTAwX3Blcm1fMS0tZnJhY19mcF8wX3Blcm1fMV8xLjEuUkRhdGEiKQpsb2FkKCIuLi9JbmZlcmVsYXRvcl9vdXRwdXRfZmlsZXMvRWNvbGlfQ29wcmFSTkFfc1JOQV9wcmlvcnMvZ2N2Ql9zaWxpY29fMV9CQlNSXzEuMV8xMDBfMC9wYXJhbXNfYW5kX2lucHV0LlJEYXRhIikKI0NyZWF0ZSBmaW5hbCBuZXR3b3JrIG1vZGVsCnNvdXJjZSgiLi4vTWlzY2VsbGFuZW91c19zY3JpcHRzL2NyZWF0ZV9maW5hbF9uZXR3b3Jrcy5SIikKI1NhdmUgdGhlIGluZmVycmVkIEdjdkIgcmVndWxvbgpHY3ZCLnJlZ3Vsb248LWNyZWF0ZS5uZXR3b3JrKCJnY3ZCX2I0NDQzXzEyIixyZWNvdmVyZWQuaW50ZXJhY3Rpb25zLm1hdHJpeCxub3ZlbC5pbnRlcmFjdGlvbnMubWF0cml4KQpHY3ZCLnJlZ3Vsb24uaWdyYXBoLmZvcm1hdDwtZ3JhcGhfZnJvbV9kYXRhX2ZyYW1lKEdjdkIucmVndWxvblssMToyXSwgdW5pb24oR2N2Qi5yZWd1bG9uWywiUmVndWxhdG9yIl0sR2N2Qi5yZWd1bG9uWywiVGFyZ2V0Il0pLCBkaXJlY3RlZCA9IFQpCnBsb3QoR2N2Qi5yZWd1bG9uLmlncmFwaC5mb3JtYXQsbGF5b3V0ID0gbGF5b3V0X25pY2VseShHY3ZCLnJlZ3Vsb24uaWdyYXBoLmZvcm1hdCksIGVkZ2UuYXJyb3cuc2l6ZSA9MC40LHZlcnRleC5sYWJlbC5jZXg9MC44LHZlcnRleC5zaXplPTIxLG1haW49IkZpZyA0RCIsdmVydGV4LnNoYXBlPWMoInNxdWFyZSIscmVwKCJjaXJjbGUiLG5yb3coR2N2Qi5yZWd1bG9uKSkpLHZlcnRleC5sYWJlbC5jb2xvcj1jKCJibHVlIixyZXAoImJsYWNrIixsZW5ndGgoZ3JlcCgicHJpb3IiLEdjdkIucmVndWxvblssM10pKSkscmVwKCJ3aGl0ZSIsbGVuZ3RoKGdyZXAoIm5vdmVsIixHY3ZCLnJlZ3Vsb25bLDNdKSkpKSkKI1Bsb3QgdGhlIGluZmVycmVkIFNwb3QgNDIgcmVndWxvbiB3aGVuIENvcHJhUk5BIHByZWRpY3Rpb25zIHdpdGggcC12YWx1ZSA8PSAwLjAxICYgYXNzb2NpYXRlZCB3aXRoIGVucmljaGVkIGZ1bmN0aW9uYWwgdGVybXMgd2VyZSB1c2VkIGFzIHByaW9ycyAoRmlnIDRFKQojTG9hZCB0aGUgb3V0cHV0IGZpbGVzIG9mIHRoZSBjb3JyZXNwb25kaW5nIEluZmVyZWxhdG9yIHJ1bgpsb2FkKCIuLi9JbmZlcmVsYXRvcl9vdXRwdXRfZmlsZXMvRWNvbGlfQ29wcmFSTkFfc1JOQV9wcmlvcnMvc3BmX3NpbGljb18zX0JCU1JfMS4xXzEwMF8wL2JldGFzX2ZyYWNfdHBfMTAwX3Blcm1fMS0tZnJhY19mcF8wX3Blcm1fMV8xLjEuUkRhdGEiKQpsb2FkKCIuLi9JbmZlcmVsYXRvcl9vdXRwdXRfZmlsZXMvRWNvbGlfQ29wcmFSTkFfc1JOQV9wcmlvcnMvc3BmX3NpbGljb18zX0JCU1JfMS4xXzEwMF8wL2NvbWJpbmVkY29uZl9mcmFjX3RwXzEwMF9wZXJtXzEtLWZyYWNfZnBfMF9wZXJtXzFfMS4xLlJEYXRhIikKbG9hZCgiLi4vSW5mZXJlbGF0b3Jfb3V0cHV0X2ZpbGVzL0Vjb2xpX0NvcHJhUk5BX3NSTkFfcHJpb3JzL3NwZl9zaWxpY29fM19CQlNSXzEuMV8xMDBfMC9wYXJhbXNfYW5kX2lucHV0LlJEYXRhIikKI0NyZWF0ZSBmaW5hbCBuZXR3b3JrIG1vZGVsCnNvdXJjZSgiLi4vTWlzY2VsbGFuZW91c19zY3JpcHRzL2NyZWF0ZV9maW5hbF9uZXR3b3Jrcy5SIikKI1NhdmUgdGhlIGluZmVycmVkIFNwb3QgNDIgcmVndWxvbgpTcG90NDIucmVndWxvbjwtY3JlYXRlLm5ldHdvcmsoInNwZl9iMzg2NF8xNSIscmVjb3ZlcmVkLmludGVyYWN0aW9ucy5tYXRyaXgsbm92ZWwuaW50ZXJhY3Rpb25zLm1hdHJpeCkKU3BvdDQyLnJlZ3Vsb24uaWdyYXBoLmZvcm1hdDwtZ3JhcGhfZnJvbV9kYXRhX2ZyYW1lKFNwb3Q0Mi5yZWd1bG9uWywxOjJdLCB1bmlvbihTcG90NDIucmVndWxvblssIlJlZ3VsYXRvciJdLFNwb3Q0Mi5yZWd1bG9uWywiVGFyZ2V0Il0pLCBkaXJlY3RlZCA9IFQpCnBsb3QoU3BvdDQyLnJlZ3Vsb24uaWdyYXBoLmZvcm1hdCxsYXlvdXQgPSBsYXlvdXRfbmljZWx5KFNwb3Q0Mi5yZWd1bG9uLmlncmFwaC5mb3JtYXQpLCBlZGdlLmFycm93LnNpemUgPTAuNCx2ZXJ0ZXgubGFiZWwuY2V4PTAuOCx2ZXJ0ZXguc2l6ZT0zMCxtYWluPSJGaWcgNEUiLHZlcnRleC5zaGFwZT1jKCJzcXVhcmUiLHJlcCgiY2lyY2xlIixucm93KFNwb3Q0Mi5yZWd1bG9uKSkpLHZlcnRleC5sYWJlbC5jb2xvcj1jKCJibHVlIixyZXAoImJsYWNrIixsZW5ndGgoZ3JlcCgicHJpb3IiLFNwb3Q0Mi5yZWd1bG9uWywzXSkpKSxyZXAoIndoaXRlIixsZW5ndGgoZ3JlcCgibm92ZWwiLFNwb3Q0Mi5yZWd1bG9uWywzXSkpKSkpCmBgYAo0LiBDcmVhdGUgc1JOQSByZWd1bG9ucyBzaG93biBpbiBGaWcgNS4gVGhpcyBmaWd1cmUgd2FzIGNyZWF0ZWQgaW4gQ3l0b3NjYXBlLiBIZXJlIHdlIHVzZSB0aGUgaWdyYXBoIHBhY2thZ2UgdG8gZ2V0IHJhdyBkcmFmdHMuCmBgYHtyfQojTG9hZCB0aGUgb3V0cHV0IGZpbGVzIG9mIHRoZSBJbmZlcmVsYXRvciBydW4gZm9yIEUuIGNvbGkKbG9hZCgiLi4vSW5mZXJlbGF0b3Jfb3V0cHV0X2ZpbGVzL0Vjb2xpXzhzUk5Bcy9iZXRhc19mcmFjX3RwXzEwMF9wZXJtXzEtLWZyYWNfZnBfMF9wZXJtXzFfMS4xLlJEYXRhIikKbG9hZCgiLi4vSW5mZXJlbGF0b3Jfb3V0cHV0X2ZpbGVzL0Vjb2xpXzhzUk5Bcy9jb21iaW5lZGNvbmZfZnJhY190cF8xMDBfcGVybV8xLS1mcmFjX2ZwXzBfcGVybV8xXzEuMS5SRGF0YSIpCmxvYWQoIi4uL0luZmVyZWxhdG9yX291dHB1dF9maWxlcy9FY29saV84c1JOQXMvcGFyYW1zX2FuZF9pbnB1dC5SRGF0YSIpCiNDcmVhdGUgZmluYWwgbmV0d29yayBtb2RlbApzb3VyY2UoIi4uL01pc2NlbGxhbmVvdXNfc2NyaXB0cy9jcmVhdGVfZmluYWxfbmV0d29ya3MuUiIpCiNDcmVhdGUgdGFibGUgd2l0aCBzUk5BLW1STkEgaW50ZXJhY3Rpb25zIGZvciBhbGwgZWlnaHQgc1JOQXMKc1JOQXM8LWNvbG5hbWVzKElOJHByaW9ycy5tYXQpWzE0MDoxNDddCnNSTkFzLm5ldHdvcms8LWNyZWF0ZS5uZXR3b3JrKHNSTkFzLHJlY292ZXJlZC5pbnRlcmFjdGlvbnMubWF0cml4LG5vdmVsLmludGVyYWN0aW9ucy5tYXRyaXgpCiNQbG90IHRoZSBpbmZlcnJlZCBTcG90IDQyIHJlZ3Vsb24KU3BvdDQyLnJlZ3Vsb248LXNSTkFzLm5ldHdvcmtbZ3JlcCgic3BmIixzUk5Bcy5uZXR3b3JrWywxXSksXQpTcG90NDIucmVndWxvbi5pZ3JhcGguZm9ybWF0PC1ncmFwaF9mcm9tX2RhdGFfZnJhbWUoU3BvdDQyLnJlZ3Vsb25bLDE6Ml0sIHVuaW9uKFNwb3Q0Mi5yZWd1bG9uWywiUmVndWxhdG9yIl0sU3BvdDQyLnJlZ3Vsb25bLCJUYXJnZXQiXSksIGRpcmVjdGVkID0gVCkKcGxvdChTcG90NDIucmVndWxvbi5pZ3JhcGguZm9ybWF0LGxheW91dCA9IGxheW91dF9uaWNlbHkoU3BvdDQyLnJlZ3Vsb24uaWdyYXBoLmZvcm1hdCksIGVkZ2UuYXJyb3cuc2l6ZSA9MC40LHZlcnRleC5sYWJlbC5jZXg9MSx2ZXJ0ZXguc2l6ZT0zMCxtYWluPSJGaWcgNUEiLHZlcnRleC5zaGFwZT1jKCJzcXVhcmUiLHJlcCgiY2lyY2xlIixucm93KFNwb3Q0Mi5yZWd1bG9uKSkpLHZlcnRleC5sYWJlbC5jb2xvcj1jKCJibHVlIixyZXAoImJsYWNrIixsZW5ndGgoZ3JlcCgicHJpb3IiLFNwb3Q0Mi5yZWd1bG9uWywzXSkpKSxyZXAoIndoaXRlIixsZW5ndGgoZ3JlcCgibm92ZWwiLFNwb3Q0Mi5yZWd1bG9uWywzXSkpKSkpCiNQbG90IHRoZSBpbmZlcnJlZCBHY3ZCIHJlZ3Vsb24KR2N2Qi5yZWd1bG9uPC1zUk5Bcy5uZXR3b3JrW2dyZXAoImdjdkIiLHNSTkFzLm5ldHdvcmtbLDFdKSxdCkdjdkIucmVndWxvbi5pZ3JhcGguZm9ybWF0PC1ncmFwaF9mcm9tX2RhdGFfZnJhbWUoR2N2Qi5yZWd1bG9uWywxOjJdLCB1bmlvbihHY3ZCLnJlZ3Vsb25bLCJSZWd1bGF0b3IiXSxHY3ZCLnJlZ3Vsb25bLCJUYXJnZXQiXSksIGRpcmVjdGVkID0gVCkKcGxvdChHY3ZCLnJlZ3Vsb24uaWdyYXBoLmZvcm1hdCxsYXlvdXQgPSBsYXlvdXRfbmljZWx5KEdjdkIucmVndWxvbi5pZ3JhcGguZm9ybWF0KSwgZWRnZS5hcnJvdy5zaXplID0wLjQsdmVydGV4LmxhYmVsLmNleD0xLHZlcnRleC5zaXplPTMwLG1haW49IkZpZyA1QiIsdmVydGV4LnNoYXBlPWMoInNxdWFyZSIscmVwKCJjaXJjbGUiLG5yb3coR2N2Qi5yZWd1bG9uKSkpLHZlcnRleC5sYWJlbC5jb2xvcj1jKCJibHVlIixyZXAoImJsYWNrIixsZW5ndGgoZ3JlcCgicHJpb3IiLEdjdkIucmVndWxvblssM10pKSkscmVwKCJ3aGl0ZSIsbGVuZ3RoKGdyZXAoIm5vdmVsIixHY3ZCLnJlZ3Vsb25bLDNdKSkpKSkKI1Bsb3QgdGhlIGluZmVycmVkIFByckYgcmVndWxvbiBpbiBQLiBhZXJ1Z2lub3NhCiNMb2FkIHRoZSBvdXRwdXQgZmlsZXMgb2YgdGhlIEluZmVyZWxhdG9yIHJ1biBmb3IgUC4gYWVydWdpbm9zYQpsb2FkKCIuLi9JbmZlcmVsYXRvcl9vdXRwdXRfZmlsZXMvUHJyRl9QYWVydWdpbm9zYS9iZXRhc19mcmFjX3RwXzEwMF9wZXJtXzEtLWZyYWNfZnBfMF9wZXJtXzFfMS4xLlJEYXRhIikKbG9hZCgiLi4vSW5mZXJlbGF0b3Jfb3V0cHV0X2ZpbGVzL1ByckZfUGFlcnVnaW5vc2EvY29tYmluZWRjb25mX2ZyYWNfdHBfMTAwX3Blcm1fMS0tZnJhY19mcF8wX3Blcm1fMV8xLjEuUkRhdGEiKQpsb2FkKCIuLi9JbmZlcmVsYXRvcl9vdXRwdXRfZmlsZXMvUHJyRl9QYWVydWdpbm9zYS9wYXJhbXNfYW5kX2lucHV0LlJEYXRhIikKI0NyZWF0ZSBmaW5hbCBuZXR3b3JrIG1vZGVsCnNvdXJjZSgiLi4vTWlzY2VsbGFuZW91c19zY3JpcHRzL2NyZWF0ZV9maW5hbF9uZXR3b3Jrcy5SIikKI0NyZWF0ZSB0YWJsZSB3aXRoIFByckYtbVJOQSBpbnRlcmFjdGlvbnMgClByckYucmVndWxvbjwtY3JlYXRlLm5ldHdvcmsoIlByckYiLHJlY292ZXJlZC5pbnRlcmFjdGlvbnMubWF0cml4LG5vdmVsLmludGVyYWN0aW9ucy5tYXRyaXgpClByckYucmVndWxvbi5pZ3JhcGguZm9ybWF0PC1ncmFwaF9mcm9tX2RhdGFfZnJhbWUoUHJyRi5yZWd1bG9uWywxOjJdLCB1bmlvbihQcnJGLnJlZ3Vsb25bLCJSZWd1bGF0b3IiXSxQcnJGLnJlZ3Vsb25bLCJUYXJnZXQiXSksIGRpcmVjdGVkID0gVCkKcGxvdChQcnJGLnJlZ3Vsb24uaWdyYXBoLmZvcm1hdCxsYXlvdXQgPSBsYXlvdXRfbmljZWx5KFByckYucmVndWxvbi5pZ3JhcGguZm9ybWF0KSwgZWRnZS5hcnJvdy5zaXplID0wLjQsdmVydGV4LmxhYmVsLmNleD0wLjY1LHZlcnRleC5zaXplPTMwLG1haW49IkZpZyA1QyIsdmVydGV4LnNoYXBlPWMoInNxdWFyZSIscmVwKCJjaXJjbGUiLG5yb3coUHJyRi5yZWd1bG9uKSkpLHZlcnRleC5sYWJlbC5jb2xvcj1jKCJibHVlIixyZXAoImJsYWNrIixsZW5ndGgoZ3JlcCgicHJpb3IiLFByckYucmVndWxvblssM10pKSkscmVwKCJ3aGl0ZSIsbGVuZ3RoKGdyZXAoIm5vdmVsIixQcnJGLnJlZ3Vsb25bLDNdKSkpKSkKI1Bsb3QgdGhlIGluZmVycmVkIEZzckEgcmVndWxvbiBpbiBCLiBzdWJ0aWxpcwojTG9hZCB0aGUgb3V0cHV0IGZpbGVzIG9mIHRoZSBJbmZlcmVsYXRvciBydW4gZm9yIEIuIHN1YnRpbGlzCmxvYWQoIi4uL0luZmVyZWxhdG9yX291dHB1dF9maWxlcy9Gc3JBX0JzdWJ0aWxpcy9iZXRhc19mcmFjX3RwXzEwMF9wZXJtXzEtLWZyYWNfZnBfMF9wZXJtXzFfMS4xLlJEYXRhIikKbG9hZCgiLi4vSW5mZXJlbGF0b3Jfb3V0cHV0X2ZpbGVzL0ZzckFfQnN1YnRpbGlzL2NvbWJpbmVkY29uZl9mcmFjX3RwXzEwMF9wZXJtXzEtLWZyYWNfZnBfMF9wZXJtXzFfMS4xLlJEYXRhIikKbG9hZCgiLi4vSW5mZXJlbGF0b3Jfb3V0cHV0X2ZpbGVzL0ZzckFfQnN1YnRpbGlzL3BhcmFtc19hbmRfaW5wdXQuUkRhdGEiKQojQ3JlYXRlIGZpbmFsIG5ldHdvcmsgbW9kZWwKc291cmNlKCIuLi9NaXNjZWxsYW5lb3VzX3NjcmlwdHMvY3JlYXRlX2ZpbmFsX25ldHdvcmtzLlIiKQojQ3JlYXRlIHRhYmxlIHdpdGggUHJyRi1tUk5BIGludGVyYWN0aW9ucyAKRnNyQS5yZWd1bG9uPC1jcmVhdGUubmV0d29yayhGc3JBLHJlY292ZXJlZC5pbnRlcmFjdGlvbnMubWF0cml4LG5vdmVsLmludGVyYWN0aW9ucy5tYXRyaXgpCiNSZXBsYWNlIGxvY3VzIElEIHdpdGggY29tbW9uIHNSTkEgbmFtZQpGc3JBLnJlZ3Vsb25bLDFdPC0iRnNyQSIKRnNyQS5yZWd1bG9uLmlncmFwaC5mb3JtYXQ8LWdyYXBoX2Zyb21fZGF0YV9mcmFtZShGc3JBLnJlZ3Vsb25bLDE6Ml0sIHVuaW9uKEZzckEucmVndWxvblssIlJlZ3VsYXRvciJdLEZzckEucmVndWxvblssIlRhcmdldCJdKSwgZGlyZWN0ZWQgPSBUKQpwbG90KEZzckEucmVndWxvbi5pZ3JhcGguZm9ybWF0LGxheW91dCA9IGxheW91dF9uaWNlbHkoRnNyQS5yZWd1bG9uLmlncmFwaC5mb3JtYXQpLCBlZGdlLmFycm93LnNpemUgPTAuNCx2ZXJ0ZXgubGFiZWwuY2V4PTAuNTUsdmVydGV4LnNpemU9MzIsbWFpbj0iRmlnIDVEIix2ZXJ0ZXguc2hhcGU9Yygic3F1YXJlIixyZXAoImNpcmNsZSIsbnJvdyhGc3JBLnJlZ3Vsb24pKSksdmVydGV4LmxhYmVsLmNvbG9yPWMoImJsdWUiLHJlcCgiYmxhY2siLGxlbmd0aChncmVwKCJwcmlvciIsRnNyQS5yZWd1bG9uWywzXSkpKSxyZXAoIndoaXRlIixsZW5ndGgoZ3JlcCgibm92ZWwiLEZzckEucmVndWxvblssM10pKSkpKQojUGxvdCB0aGUgaW5mZXJyZWQgUnNhRSByZWd1bG9uIGluIFMuIGF1cmV1cwojTG9hZCB0aGUgb3V0cHV0IGZpbGVzIG9mIHRoZSBJbmZlcmVsYXRvciBydW4gZm9yIFMuIGF1cmVzCmxvYWQoIi4uL0luZmVyZWxhdG9yX291dHB1dF9maWxlcy9Sc2FFX1NhdXJldXMvYmV0YXNfZnJhY190cF8xMDBfcGVybV8xLS1mcmFjX2ZwXzBfcGVybV8xXzEuMS5SRGF0YSIpCmxvYWQoIi4uL0luZmVyZWxhdG9yX291dHB1dF9maWxlcy9Sc2FFX1NhdXJldXMvY29tYmluZWRjb25mX2ZyYWNfdHBfMTAwX3Blcm1fMS0tZnJhY19mcF8wX3Blcm1fMV8xLjEuUkRhdGEiKQpsb2FkKCIuLi9JbmZlcmVsYXRvcl9vdXRwdXRfZmlsZXMvUnNhRV9TYXVyZXVzL3BhcmFtc19hbmRfaW5wdXQuUkRhdGEiKQojQ3JlYXRlIGZpbmFsIG5ldHdvcmsgbW9kZWwKc291cmNlKCIuLi9NaXNjZWxsYW5lb3VzX3NjcmlwdHMvY3JlYXRlX2ZpbmFsX25ldHdvcmtzLlIiKQojQ3JlYXRlIHRhYmxlIHdpdGggUnNhRS1tUk5BIGludGVyYWN0aW9ucyAKUnNhRS5yZWNvdmVyZWQudGFyZ2V0czwtbmFtZXMod2hpY2gocmVjb3ZlcmVkLmludGVyYWN0aW9ucy5tYXRyaXhbLFJzYUVdIT0wKSkKUnNhRS5yZWNvdmVyZWQudGFyZ2V0czwtc2FwcGx5KDE6bGVuZ3RoKFJzYUUucmVjb3ZlcmVkLnRhcmdldHMpLCBmdW5jdGlvbih4KXtnc3ViKCJTQU9VSFNDIiwiU0EiLFJzYUUucmVjb3ZlcmVkLnRhcmdldHNbeF0pfSkKUnNhRS5ub3ZlbC50YXJnZXRzPC1uYW1lcyh3aGljaChub3ZlbC5pbnRlcmFjdGlvbnMubWF0cml4WyxSc2FFXSE9MCkpClJzYUUubm92ZWwudGFyZ2V0czwtc2FwcGx5KDE6bGVuZ3RoKFJzYUUubm92ZWwudGFyZ2V0cyksIGZ1bmN0aW9uKHgpe2dzdWIoIlNBT1VIU0MiLCJTQSIsUnNhRS5ub3ZlbC50YXJnZXRzW3hdKX0pClJzYUUucmVndWxvbjwtcmJpbmQoY2JpbmQocmVwKCJSc2FFIixsZW5ndGgoUnNhRS5yZWNvdmVyZWQudGFyZ2V0cykpLFJzYUUucmVjb3ZlcmVkLnRhcmdldHMscmVwKCJwcmlvcnMiLGxlbmd0aChSc2FFLnJlY292ZXJlZC50YXJnZXRzKSkpLGNiaW5kKHJlcCgiUnNhRSIsbGVuZ3RoKFJzYUUubm92ZWwudGFyZ2V0cykpLFJzYUUubm92ZWwudGFyZ2V0cyxyZXAoIm5vdmVsIixsZW5ndGgoUnNhRS5ub3ZlbC50YXJnZXRzKSkpKQpjb2xuYW1lcyhSc2FFLnJlZ3Vsb24pPC1jKCJSZWd1bGF0b3IiLCJUYXJnZXQiLCJJbnRlcmFjdGlvbiIpClJzYUUucmVndWxvbi5pZ3JhcGguZm9ybWF0PC1ncmFwaF9mcm9tX2RhdGFfZnJhbWUoUnNhRS5yZWd1bG9uWywxOjJdLCB1bmlvbihSc2FFLnJlZ3Vsb25bLCJSZWd1bGF0b3IiXSxSc2FFLnJlZ3Vsb25bLCJUYXJnZXQiXSksIGRpcmVjdGVkID0gVCkKcGxvdChSc2FFLnJlZ3Vsb24uaWdyYXBoLmZvcm1hdCxsYXlvdXQgPSBsYXlvdXRfbmljZWx5KFJzYUUucmVndWxvbi5pZ3JhcGguZm9ybWF0KSwgZWRnZS5hcnJvdy5zaXplID0wLjQsdmVydGV4LmxhYmVsLmNleD0wLjU1LHZlcnRleC5zaXplPTMyLG1haW49IkZpZyA1RSIsdmVydGV4LnNoYXBlPWMoInNxdWFyZSIscmVwKCJjaXJjbGUiLG5yb3coUnNhRS5yZWd1bG9uKSkpLHZlcnRleC5sYWJlbC5jb2xvcj1jKCJibHVlIixyZXAoImJsYWNrIixsZW5ndGgoZ3JlcCgicHJpb3IiLFJzYUUucmVndWxvblssM10pKSkscmVwKCJ3aGl0ZSIsbGVuZ3RoKGdyZXAoIm5vdmVsIixSc2FFLnJlZ3Vsb25bLDNdKSkpKSkKYGBgCgoK